Bem-vindo ao treinamento de mensageria, JMS e ActiveMQ.
Bom, temos uma loja virtual que já está no ar há algum tempo. Produtos são colocados em um carrinho de compra e no final o pedido é finalizado. Quando a compra é finalizada, enviamos os dados da compra para outro sistema responsável pela geração da nota. Até aí tudo bem.
Sabemos que eventos promocionais com black friday aumentam o número de acesso vertiginosamente. Queremos que nossa aplicação funcione, mas o problema é que o outro sistema pode falhar, inclusive pode haver algum problema de comunicação na rede e também ele pode não aguentar processar um grande número de informações enviadas. Não podemos perder um pedido só porque o sistema de geração de notas não funciona.
Para evitarmos os problemas que foram citados, precisamos desacoplar os dois sistemas através de um bloco arquitetural que ficará entre ambos. É uma espécie de servidor entre dois sistemas. Esse servidor é chamado de middleware e com ele o a loja virtual não conversa mais diretamente com o sistema de geração de notas fiscais. O objetivo do middleware é desacoplar os dois lados, isto é, as duas aplicações.
Agora, a loja enviará o pedido empacotando-o dentro de um envelope para o middleware que guardará a mensagem recebida e algum momento depois a entregará para o sistema de nota fiscal (assíncrono). Esse processo é orientado à mensagens, por isso que é chamado de MOM (Message Oriented Middleware).
Então, dentro do que vimos, percebemos o desacoplamento arquitetural entre a loja e o sistema de notas (um sistema deixar de conhecer o outro) e todo comunicação é via mensagem. A mensagem é recebida pelo middleware e algum momento posterior, é entregue para o sistema destinarário. Justamente por ser “um momento posterior” tudo ocorre assincronamente, pois não sabemos quando a mensagem será entregue.
Para implementarmos essa solução, precisamos de um middleware e o mais famoso no mundo Java se chama ActiveMQ da Apache Foundation. Usaremos o ActiveMQ ao longo deste treinamento, um MOM da Apache.
Primeiro passo é instalar o ActiveMQ.
Baixamos o ActiveMQ 5.12.x (ou mais recente) em http://activemq.apache.org/download.html.
Observação: No Windows é preciso executar o script InstallService.bat
da pasta win32
ou win64
dependendo da arquitetura do computador.
Depois de baixado, só precisamos descompactá-lo. Como todo servidor, precisamos rodá-lo e fazemos através do terminal entrando na pasta apache-activemq-5.12.2/bin
. Lá uma série de scripts e precisamos rodar aquele que condiz com o sistema operacional que estamos usando. Por exemplo, no OSX usamos no terminal o comando
sh activemq
Só que não foi dessa vez. A razão é que precisamos passar parâmetros para esse script. Usarmos a opção console:
sh activemq console
Agora sim. Além de subir nosso servidor, ele nos apresenta uma série de logs. O terminal também indica o endereço do nosso servidor: http://localhost:8161
Visualizamos a página principal do ActiveMQ. Há um link (http://localhost:8161/admin) para o console de administrar. Ao ser clicado, precisamos um usuário e uma senha. O login e senha padrão são admin
.
É bem simples, porém há informações que já são úteis como o nome da máquina que está rodando, versão do servidor, etc. Podemos até enviar já mensagens através do link send. Há também duas opções, queues e topics. Vamos focar no primeiro, pois nossa loja quer enviar uma mensagem com o pedido empacotado a esse MOM. O MOM poderia ter vários outros clientes, isto é, aplicações. Não simplesmente entregamos a mensagem para o MOM, nós indicamos também qual o destino desta mensagem. A mensagem do pedido enviado para o MOM fica cadastrado dentro de uma fila (queue) para o ActiveMQ organizar, inclusive poderíamos ter várias filas. O topic, que não vamos utilizar agora, é um outro destino.
Clicando em queue, é perguntada o nome da fila que chamaremos de financeiro. Podemos acessar a fila criada e seus consumidores (quem gostaria de receber) e os active producers, quem está enviando. Há uma opção de enviar uma mensagem para a fila e é exatamente o que faremos.
Na tela de envio de mensagem, precisamos informar qual é o destino, mas não apenas isso. Há um monte de cabeçalhos da mensagem que podemos preencher quando necessário.
Na caixa “Message Body” vamos escrever: Oi mundo mensageria!
Uma mensagem foi enviada, ela está enqueued. Isso signiica que a fila recebeu e guardou, salva. Que tal enviarmos mais uma mensagem? Dessa vez será “Oi! Mensageria segunda mensagem”. As mensagem ficam enqueued, mas nenhum foi entregue pois ainda não temos um consumidor.
Vamos simular essa entrega para nossa aplicação de nota fiscal que tem interesse em receber essas mensagens. Para isso, preparamos um jar com código Java que consumirá a mensagem, mas ele não possui todo o protocolo possível do ActiveMQ, é por isso que da pasta do ActiveMQ que baixamos, vamos mover o activemq-all-5.12.0.jar
. Resumindo: nosso aula-jms.jar
depende de ativemq-all-5.12.0.jar
.
Sem fechar o terminal do ActiveMQ que está rodando, vamos abrir um novo terminal e executar:
No Linux e Mac:
java –cp activemq-all-5.12.0.jar:aula-jms.jar br.com.caelum.TesteMensageria consome
No Windows:
java –cp activemq-all-5.12.0.jar;aula-jms.jar br.com.caelum.TesteMensageria consome
Nosso programa se conectou ao nosso MOM e recebeu as mensagens que cadastramos.
Podemos enviar mensagens na linha de comando também usando o parâmetro envia
seguido com a quantidade de números :
No Linux e Mac:
java –cp activemq-all-5.12.0.jar:aula-jms.jar br.com.caelum.TesteMensageria envia 10
No Windows:
java –cp activemq-all-5.12.0.jar;aula-jms.jar br.com.caelum.TesteMensageria envia 10
Neste exemplo, estamos enviando 10 mensagens. Agora em nosso MOM, temos 10 mensagens. Ao testar a consumidor (recebimento das mensagens) aparece no console:
Agora vamos praticar com os exercícios do capítulo.
No primeiro capítulo, tivemos uma introdução de o que é um MOM, como ele desacopla o produtor do consumidor da mensagem, e que a entrega das mesmas é feita de forma assíncrona. Neste segundo capítulo do curso, queremos entrar nos detalhes do código, criar um consumidor e dar início a nossa aplicação.
Vimos um dos MOM's mais famosos do mundo Java, que é o ActiveMQ. Porém ele não é o único, e a própria ideia de MOM's é bem antiga. Existe uma série de servidores e middlewares no mercado, como: IBM WebSphere, WebLogic Server Messaging, HornetQ, Artemis, Apollo ...
Imagine agora, que para produzir ou consumir mensagens a partir do código java, devemos aprender sempre a API específica desses MOM's. Porém, no final, a gente sempre cria mensagem e recebe mensagem. Para facilitar o trabalho do desenvolvedor, foi criado um padrão JavaEE em cima dessa ideia de mensageria, que é o JMS (Java Messaging Service).
Continuaremos usando o ActiveMQ, porém o código que estaremos utilizando, serve também para um IBM WebSphere ou para um WebLogic Server Messaging. Muda muito pouco o código Java necessário para consumir ou escrever mensagens, e por debaixo dos panos, continuamos a usar o ActiveMQ.
Agora, vamos rapidamente subir o ActiveMQ, do mesmo jeito que foi feito na aula anterior(com o parâmetro 'console' na linha de comando) e acessar com "User Name: admin / Password: admin".
Para começar com os códigos, precisamos abrir também o eclipse JavaEE, e criar um projeto Java padrão. Usaremos o Java 1.8 como JRE e o nome será jms. Precisamos do arquivo do ActiveMQ no nosso projeto. Para isso, clique com o botão direito no projeto, New -> folder
. Chame essa pasta de lib
e então, arraste o arquivo do ActiveMQ activemq-all-5.12.0.jar
para dentro dela. Após isso, dentro do eclipse, clique com o botão direito no JAR copiado e Build Path -> Add to Build Path
.
Com a importação do .jar feita, podemos começar com o nosso código. Crie uma classe TesteConsumidor
no pacote br.com.caelum.jms
. Usaremos o tempo todo importações da biblioteca javax.jms
.
Criaremos uma conexão. Porém, da onde vem a nossa ConnectionFactory
? O MOM vai te fornecer! A ideia é que quando o MOM é inicializado, que ele ja disponibilize essa conexão dentro de um registro. Com isso, precisamos apenas pegar essa conexão dentro de um registro, e esse é o JNDI. O nome utilizado no lookup
é apresentado na documentação do MOM.
public class TesteConsumidor {
public static void main(String[] args) throws Exception{
InitialContext context = new InitialContext();
//imports do package javax.jms
ConnectionFactory factory = (ConnectionFactory) context.lookup("ConnectionFactory");
Connection connection = factory.createConnection();
connection.start();
new Scanner(System.in).nextLine(); //parar o programa para testar a conexao
connection.close();
context.close();
}
Além disso, devemos criar um arquivo jndi.properties
na pasta src
que copiamos do site do ActiveMQ:
java.naming.factory.initial = org.apache.activemq.jndi.ActiveMQInitialContextFactory
# use the following property to configure the default connector
java.naming.provider.url = vm://localhost
# use the following property to specify the JNDI name the connection factory
# should appear as.
#connectionFactoryNames = connectionFactory, queueConnectionFactory, topicConnectionFactry
# register some queues in JNDI using the form
# queue.[jndiName] = [physicalName]
queue.MyQueue = example.MyQueue
# register some topics in JNDI using the form
# topic.[jndiName] = [physicalName]
topic.MyTopic = example.MyTopic
Ao rodar o código aparentemente foi estabelecida uma conexão com ActiveMQ como previsto. Vamos verificar isso no console de administração do ActiveMQ. Para nossa supresa não aparece nenhuma conexão. O que aconteceu? A resposta está no arquivo jndi.properties
. Repare a linha:
vm://localhost
o vm
indica que o ActiveMQ subiu em memória. O ActiveMQ não precisa rodar em sua JVM dedicada. O nosso código Java não só estabeleceu uma conexão como também criou uma nova instancia do ActiveMQ! Mas com certeza isso não foi a nossa intenção pois já subimos o ActiveMQ antes separadamente. Vamos mudar isso e alterar a linha no jndi.properties
:
java.naming.provider.url = tcp://localhost:61616
Rodando nossa classe de teste, vemos que não imprime nada no console, mas ao entrarmos na console de administração do (http://localhost:8161/admin/connections.jsp) ActiveMQ -> Connections
, observamos que há uma nova conexão com o ID da sua máquina local.
Agora queremos criar um Consumer, que irá receber nossas mensagens.
public class TesteConsumidor {
//cria context, factory, connection
Session session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE);
Destination fila = (Destination) context.lookup("financeiro");
MessageConsumer consumer = session.createConsumer(fila);
Message message = consumer.receive();
System.out.println("Recebendo msg: "+ message);
session.close();
//fecha conexões
}
Ja tinhamos nossa fila de consumo, que foi criada na primeira aula. Sendo assim, o ActiveMQ disponibiliza no jndi.properties
, e acessamos pelo lookup
. Porém, precisamos configurar o arquivo de properties para ele saber o que procurar.
Dentro do JNDI, temos a linha:
# queue.[jndiName] = [physicalName]
Queue.MyQueue = example.MyQueue
Na direita, fica o nome da fila que foi criada no ActiveMQ, que no nosso caso é fila.financeiro
. Na esquerda, fica o nome na qual usaremos para referenciar essa fila no código Java. Substituindo:
queue.financeiro = fila.financeiro
Assim, ja podemos acessar o nosso consumer do ActiveMQ pelo nosso código Java. Criamos também uma Message
que irá receber uma mensagem do consumer
e printá-la no nosso console. Rodamos a classe para criar o nosso MessageConsumer
:
Agora para testar, enviamos uma mensagem através da console de administração.
E no console...
Queremos agora que nossa aplicação fique online, que o MessageConsumer
consiga receber essas mensagens o tempo todo e não só uma mensagem. Essa configuração, iremos aprender mais a frente. Agora é a hora dos exercícios.
Começando deste ponto? Você pode fazer o DOWNLOAD completo do projeto do capítulo anterior e continuar seus estudos a partir deste capítulo.
No capítulo anterior conseguimos estabelecer uma conexão utilizando a fábrica disponibilizada pelo ActiveMQ, através do InitialContext
. E a partir dessa conexão que inicializamos, criamos a nossa sessão, que faz o recebimento e a confirmação das mensagens.
Da nossa Session
, criamos um MessageConsumer
, que fica escutando mensagens da fila (Destination
) que pegamos do nosso InitialContext
. E conseguimos obter nossa mensagem através do método consumer.receive()
.
O problema que encontramos no último capítulo, é que nosso sistema recebia apenas uma mensagem e encerrava o seu funcionamento, e não é isso que queremos. Nos esperamos que ele fique escutando o tempo todo por mensagens, e para isso , devemos cadastrar um novo objeto no nosso consumer, com o responsabilidade de tratar as mensagens que recebemos.
Para manter a separação de responsabilidades, vamos fazer com o que Consumer
delegue o tratamento das mensagens para um objeto da interface MessageListener
:
consumer.setMessageListener();
E para usar esta interface, vamos utilizar uma classe anônima MessageListener
que a implementa:
consumer.setMessageListener(new MessageListener(){
});
E nesta classe devemos implementar o método chamado onMessage
, que recebe a mensagem e a faz algum processamento com ela. Por enquanto vamos apenas exibi-la no console:
consumer.setMessageListener(new MessageListener(){
@Override
public void onMessage(Message message){
System.out.println(message);
}
});
Removendo a linha System.out.println("Recebendo msg: " + message");
, podemos ir na página de envio de mensagens do ActiveMQ testar que o nosso método onMessage
funciona, e enviar diversas mensagens sem que o nosso sistema se encerre.
Repare que apesar de enviarmos apenas mensagens de texto, no nosso console aparece algo do tipo:
ActiveMQTextMessage {commandId = 7,responseRequired = false, messageId = ID, message="Sua mensagem aqui!!"}
Isto ocorre pois estamos usando a interface Message, que possui subinterfaces mais específicas, que podemos utilizar para pegar o texto da mensagem mais diretamente.
Primeiro vamos pegar a mensagem que estamos recebendo e fazer um cast dela para uma das suas subinterfaces, a TextMessage
, já que estamos trabalhando com mensagens de texto:
consumer.setMessageListener(new MessageListener(){
@Override
public void onMessage(Message message){
TextMessage textMessage = (TextMessage)message;
System.out.println(message);
}
});
Agora que temos uma TextMessage
podemos utilizar o método getText()
para pegar apenas o texto da mensagem, deixando assim o resultado mais elegante:
consumer.setMessageListener(new MessageListener(){
@Override
public void onMessage(Message message){
TextMessage textMessage = (TextMessage)message;
System.out.println(textMessage.getText());
}
});
Como esta API é um pouco antiga, o Eclipse deve reclamar dizendo que o método getText
joga uma exceção , então devemos envolve-lo com um try-catch
:
consumer.setMessageListener(new MessageListener(){
@Override
public void onMessage(Message message){
TextMessage textMessage = (TextMessage)message;
try{
System.out.println(textMessage.getText());
} catch(JMSException e){
e.printStackTrace();
}
}
});
Testando agora vemos que as nossas mensagens aparecem muito mais limpas no console:
O curso JMS e ActiveMQ: Mensageria com Java possui 167 minutos de vídeos, em um total de 75 atividades. Gostou? Conheça nossos outros cursos de Java em Programação, ou leia nossos artigos de Programação.
Matricule-se e comece a estudar com a gente hoje! Conheça outros tópicos abordados durante o curso:
Cursos de programação, UX, agilidade, data science, transformação digital, mobile, front-end, marketing e infra.
Certificado de que assistiu o curso e finalizou as atividades
Estude até mesmo offline através das nossas apps Android e iOS em smartphones e tablets
Cursos de introdução a tecnologia através de games, apps e ciência
Reforço online de inglês e espanhol para aprimorar seu conhecimento
Cursos de programação, UX, agilidade, data science, transformação digital, mobile, front-end, marketing e infra.
Certificado de que assistiu o curso e finalizou as atividades
Estude até mesmo offline através das nossas apps Android e iOS em smartphones e tablets
Cursos de introdução a tecnologia através de games, apps e ciência
Reforço online de inglês e espanhol para aprimorar seu conhecimento
Cursos de programação, UX, agilidade, data science, transformação digital, mobile, front-end, marketing e infra.
Certificado de que assistiu o curso e finalizou as atividades
Estude até mesmo offline através das nossas apps Android e iOS em smartphones e tablets
Cursos de introdução a tecnologia através de games, apps e ciência
Reforço online de inglês e espanhol para aprimorar seu conhecimento
Cursos de programação, UX, agilidade, data science, transformação digital, mobile, front-end, marketing e infra.
Certificado de que assistiu o curso e finalizou as atividades
Estude até mesmo offline através das nossas apps Android e iOS em smartphones e tablets
Cursos de introdução a tecnologia através de games, apps e ciência
Reforço online de inglês e espanhol para aprimorar seu conhecimento
Acesso completo
durante 1 ano
Estude 24h/dia
onde e quando quiser
Novos cursos
todas as semanas