Teremos dois aplicativos java baseados em Spring.
O primeiro é um aplicativo Spring MVC (chamaremos de Web-Shop) onde você pode comprar um produto on-line.
O outro será o aplicativo de Inventário (chamaremos de Order-Inventory), baseado no Spring MVC, implantado como war.
Depois de ter feito seu pedido (significa que o status do pedido é 'criado'),
O aplicativo de loja virtual (Web-Shop) envia este pedido para o aplicativo de Inventário
Ele envia via ActiveMQ Message Broker usando a fila JMS (nomeada como 'order-queue'),
Configuramos um Listener na fila de resposta (nomeado como 'order-response-queue')
para obter a confirmação do pedido a partir do aplicativo de inventário.
O aplicativo de inventário, que estará escutando a fila de pedidos ("order-queue"),
obtém o pedido e o processa.
Em seguida, envia a confirmação na fila de resposta ("order-response-queue").
Ao receber a resposta do pedido, o Web-shop atualiza o status do pedido no repositório.
Em Resumo:
Web-Shop envia pedido -> usando 'order-queue'
Order-Inventory <- escuta 'order-queue'
Order-Inventory recebe o pedido, processa, retorna
Order-Inventory envia a confirmação -> usando 'order-response-queue'
Web-Shop escuta <- 'order-response-queue'
Web-Shop recebe a confirmação e atualiza o status do pedido
Fazendo os downloads:
Baixe o ActiveMQ Classic em [https://activemq.apache.org/components/classic/download/]
Baixe o JDK 8 em [https://www.oracle.com/technetwork/java/javase/downloads/java-archive-downloads-javase7-521261.html]
Configurando o ambiente:
Descompacte o ActiveMQ numa pasta.
Vamos configurar as variáveis de ambiente para linux, ou para git bash para windows
Irei fazer de um modo portável, crie um arquivo de configuração: (setenv.sh)
e coloque o conteúdo:
export JAVA_HOME=/f/java/jdk8
export TOMCAT_HOME=/f/java/apache/tomcat
export ACTIVEMQ_HOME=/f/java/apache/activemq
export PATH=$PATH;$JAVA_HOME/bin;$ACTIVEMQ_HOME/bin;$TOMCAT_HOME/bin
Agora executamos o arquivo com o comando: $ . ./setenv.sh
Vamos iniciar o ActiveMQ: $ ./activemq start
Entre no browser em: http://localhost:8161/admin/
Entre com o usuário e senha: admin e admin
Obs: eu tive problema com a porta 5672, então mudei a porta amqp de 5672 para 5676.
isso aconteceu por que o meu ERLang Server estava rodando nessa porta também.
se for necessário, entre em %activemq_home%\conf\activemq.xml
1. ConnectionFactory:
Para conectar-se a um Message Broker (e enviar e receber mensagens), precisamos configurar um ConnectionFactory.
ActiveMQConnectionFactory é a implementação do ConnectionFactory do Apache.
2. Destino:
Cada mensagem JMS enviada por um aplicativo é endereçada com um Destino.
Os destinos no JMS são como caixas postais em que as mensagens são colocadas até que alguém venha buscá-las.
Existem dois tipos de destino no JMS: fila e tópico.
em inglês: queue e topic.
Filas "point-to-point":
As filas são baseadas no modelo de mensagens ponto-a-ponto, no qual as mensagens são enviadas para uma fila.
Cada mensagem tem exatamente um remetente e um receptor.
A mensagem é garantida para ser entregue a apenas um receptor.
Tópicos "publish-subscribe":
Os tópicos são baseados no modelo de publicação-assinatura, no qual as mensagens são enviadas para um tópico.
N assinantes podem ser inscritos em um tópico e, quando uma mensagem chegar, cada um receberá uma cópia dessa mensagem.
3. JmsTemplate:
Configuramos um JmsTemplate que fornece uma abstração, ocultando todas as complexidades da comunicação JMS.
Sem o JmsTemplate, você será forçado a criar conexões/sessões/MessageProducers/MessageConsumers
e capturar todas as exceções desagradáveis que puderem ser lançadas.
Com o JmsTemplate, você obtém APIs simples para trabalhar e, por trás dos bastidores ele cuida de todas as complexidades do JMS.
Ele cuida de criar a conexão, obter a sessão e, finalmente, enviar (assim como a recepção síncrona) da mensagem.
Nós estaremos usando o JmsTemplate para enviar a mensagem.
Observe que o JmsTemplate também oferece possibilidades de recebimento de mensagens, mas é síncrono (ele bloqueia o aplicativo de escuta) e geralmente não é preferido quando a comunicação assíncrona é possível.
4. Listeners de mensagens:
Ainda precisamos fazer a configuração para a escuta de mensagens no destino.
Poderíamos ter usado a interface padrão javax.jms.MessageListener
, mas o Spring fornece a possibilidade de configurar listeners usando POJOs
simples, sem implementar uma interface.
Para usar isso:
-
- Anote um método POJO com
@JmsListener
do Spring.
- Anote um método POJO com
-
- Configure um message-listener-container (usando
JmsListenerContainerFactory
):
Que escuta em um destino (pode ser aquele usado com@JmsListener
) e quando qualquer mensagem chega nesse destino, ele recupera essa mensagem e passa para o bean anotado com@JmsListener
para esse destino.
- Configure um message-listener-container (usando
-
- Use
@EnableJms
, que permite a detecção de anotações JmsListener em qualquer bean gerenciado pelo Spring no container.
- Use
DefaultJmsListenerContainerFactory
é uma implementação de JmsListenerContainerFactory
para construir um DefaultMessageListenerContainer
habitual.
Você pode configurar diversas propriedades.
No mínimo, precisa de uma fábrica de conexões.
Além disso, especificamos a simultaneidade (número máximo de usuários / consumidores simultâneos) usando setConcurrency
(“lower-upper”).
Você também pode usar setConcurrency
(“upper”), o que significa que o menor será 1.
Nota: A Configuração de Mensagens para a Inventory Application é exatamente igual a esta, com a fila sendo invertida:
o pedido será recebido na fila de pedidos e a resposta será enviada para a file pedido-resposta.
Abaixo está um passo-a-passo das configurações cruciais para a configuração da mensageria:
configure as duas bibliotecas, uma para o spring tratar jms: spring-jms
e a outra para o active-mq: activemq-spring
Configure o Spring para entender as classes de configuração: MessagingConfiguration
e MessagingListnerConfiguration
Configure os Beans para depois serem injetados, a connectionFactory, e o jmsTemplate
A connectionFactory basicamente informa o endereço do servidor activemq.
Já o jmsTemplate vem configurando a fila.
Na classe MessagingListenerConfiguration
usa-se a annotation @EnableJms e injeta a connectionFactory.
E também cria-se um Bean com o jmsListenerContainerFactory informando a quantidade de usuário concorrentes.
Configura-se um @JmsListener com a fila que irá escutar.
Nesse método receiveMessage chama-se dentro do serviço o MessageSender.
O MessageSender executa o sendMessage para enviar para o servidor ActiveMQ
Na classe MessageSender injeta-se o jmsTemplate que tem o método send.
Ele cria a mensagem com o objeto CreateMessage, executa o método createMessage, e utiliza a session do activeMQ.
Foi utilizado o método createObjectMessage da session do jms, visto que estamos serializando um objeto java.
Não fiz usando Json por falta de tempo, mas prefiro serializar em json em texto, e gravar com createTextMessage.
Assim, a mensagem fica independente de linguagem (usando o protocolo AMQP) e fica mais fácil gerenciar também, é possível ver as mensagem e ler nos consoles dos MQ servers.
Outros métodos são: c
reateTextMessage para enviar um texto,
createStreamMessage para enviar stream de tipos primitivos do java,
createMapMessage para enviar pares de nomes-valores,
createBytesMessage para enviar uma mensagem contendo bytes.
Vamos simular primeiro o envio da mensagem, deixar pendente, e depois subir o projeto Order-Inventory para consumir a mensagem:
visite: http://localhost:8080/Spring4MVCJmsActiveMQExample/
Primeiro, sem o deploy do projeto Order-Inventory:
Entramos no sistema e criamos uma mensagem (um pedido):
Agora o "Café" está pendente, vamos fazer o deploy da aplicação Order-Iventory para que o pedido seja processado:
No admin do ActiveMQ, veremos os pedidos que foram enviados para a fila (queue) e processados:
código fonte no meu repositório:
https://github.com/danilobatistaqueiroz/ActiveMQ_SpringMVC_JMS
referência:
http://websystique.com/springmvc/spring-4-mvc-jms-activemq-annotation-based-example/