Comunicação remota com JMS e ActiveMQ
1. Visão geral
Vimos emprevious article comoSpring Remoting poderia ser usado para fornecerRPC no topo de um canal assíncrono como uma filaAMQP. No entanto, podemos obter o mesmo resultado usandoJMS também.
Neste artigo, vamos, de fato, explorar como configurar a invocação remota usandoSpring Remoting JMSeApache ActiveMQ como um middleware de mensagens.
2. Iniciando um Apache ActiveMQ Broker
Apache ActiveMQ é umopen source message broker que permite aos aplicativos trocar informações de forma assíncrona e é totalmente compatível comJava Message ServiceAPI.
Para executar nosso experimento, primeiro precisamos configurar uma instância em execução deActiveMQ. Podemos escolher entre várias maneiras: seguindo as etapas descritas emofficial guide, incorporando-o em um aplicativoJava ou mais simplesmente girando um contêinerDocker com o seguinte comando:
docker run -p 61616:61616 -p 8161:8161 rmohr/activemq:5.14.3
Isso iniciará um contêinerActiveMQ que expõe na porta 8081 uma interface de usuário web de administração simples, por meio da qual podemos verificar as filas disponíveis, clientes conectados e outras informações administrativas. JMS clientes precisarão usar a porta 61616 para se conectar ao broker e trocar mensagens.
3. Dependências do Maven
Como nos artigos anteriores cobrindoSpring Remoting, vamos configurar um servidor e um clienteSpring Boot aplicativos para mostrar comoJMS Remoting funciona.
Como geralmente escolhemos cuidadosamente as dependências iniciais deSpring Boot,as explained here:
org.springframework.boot
spring-boot-starter-activemq
org.springframework.boot
spring-boot-starter-tomcat
Excluímos explicitamente ospring-boot-starter-tomcat para não ter os arquivosTomcat relacionados com.jar no classpath.
Isso, por sua vez, impedirá que o mecanismo de autoconfiguração deSpring Boot inicie um servidor da web incorporado quando o aplicativo for inicializado, pois não precisamos dele.
4. Aplicativo de servidor
4.1. Exponha o serviço
Vamos configurar um aplicativo de servidor que expõe osCabBookingService que os clientes poderão invocar.
The first step is to declare a bean that implements the interface of the service we want to expose to the clients. Este é o bean que executará a lógica de negócios no servidor:
@Bean
CabBookingService bookingService() {
return new CabBookingServiceImpl();
}
Vamos então definir a fila da qual o servidor irá recuperar as invocações, especificando seu nome no construtor:
@Bean
Queue queue() {
return new ActiveMQQueue("remotingQueue");
}
Como já sabemos dos artigos anteriores,one of the main concepts of Spring Remoting is the Service Exporter, the component that collects the invocation requests from some source, neste caso, uma filaApacheMQ ─ e invoca o método desejado na implementação do serviço.
Para trabalhar comJMS, definimos umJmsInvokerServiceExporter:
@Bean
JmsInvokerServiceExporter exporter(CabBookingService implementation) {
JmsInvokerServiceExporter exporter = new JmsInvokerServiceExporter();
exporter.setServiceInterface(CabBookingService.class);
exporter.setService(implementation);
return exporter;
}
Finalmente, precisamos definir um ouvinte que tenha a responsabilidade de consumir mensagens. Olistener acts as a bridge between ApacheMQ and the*JmsInvokerServiceExporter*, que escuta as mensagens de invocação disponíveis na fila, encaminha a invocação ao exportador de serviço e serializa de volta os resultados:
@Bean SimpleMessageListenerContainer listener(
ConnectionFactory factory,
JmsInvokerServiceExporter exporter) {
SimpleMessageListenerContainer container = new SimpleMessageListenerContainer();
container.setConnectionFactory(factory);
container.setDestinationName("remotingQueue");
container.setConcurrentConsumers(1);
container.setMessageListener(exporter);
return container;
}
4.2. Configuração
Vamos lembrar de configurar o arquivoapplication.properties para permitir queSpring Boot configure alguns objetos básicos, como por exemplo oConnectionFactory necessário para o ouvinte. Os valores dos vários parâmetros dependem principalmente da maneira como
Os valores dos vários parâmetros dependem principalmente da maneira comoApacheMQ foi instalado, e o seguinte é uma configuração razoável para nosso contêinerDocker em execução na mesma máquina onde executaremos estes exemplos:
spring.activemq.broker-url=tcp://localhost:61616
spring.activemq.packages.trusted=org.springframework.remoting.support,java.lang,com.example.api
O parâmetrospring.activemq.broker-url é uma referência à portaAMQ. Uma explicação mais profunda é necessária paraspring.activemq.packages.trusted parameter. Desde a versão 5.12.2, o ActiveMQ recusa por padrão qualquer mensagem do tipo
A partir da versão 5.12.2, o ActiveMQ recusa por padrão qualquer mensagem do tipoObjectMessage, usada para trocar o objetoJava serializado porque é considerado um vetor potencial para um ataque à segurança em alguns contextos.
De qualquer forma, é possível instruirAMQ a aceitar objetos serializados em pacotes especificados. org.springframework.remoting.support é o pacote que contém as mensagens principais que representam a invocação de um método remoto e seu resultado. O pacote
O pacotecom.example.api contém os parâmetros e os resultados do nosso serviço. java.lang é adicionado porque o objeto que representa o resultado da reserva de táxi faz referência aString, portanto, precisamos serializá-lo também.
5. Aplicativo Cliente
5.1. Chame o serviço remoto
Vamos abordar o cliente agora. Novamente, precisamos definir a fila na qual as mensagens de chamada serão gravadas. Precisamos verificar novamente se o cliente e o servidor usam o mesmo nome.
@Bean
Queue queue() {
return new ActiveMQQueue("remotingQueue");
}
Precisamos então configurar um exportador:
@Bean
FactoryBean invoker(ConnectionFactory factory, Queue queue) {
JmsInvokerProxyFactoryBean factoryBean = new JmsInvokerProxyFactoryBean();
factoryBean.setConnectionFactory(factory);
factoryBean.setServiceInterface(CabBookingService.class);
factoryBean.setQueue(queue);
return factoryBean;
}
Agora podemos usar o serviço remoto como se fosse declarado como um bean local:
CabBookingService service = context.getBean(CabBookingService.class);
out.println(service.bookRide("13 Seagate Blvd, Key Largo, FL 33037"));
5.2. Execute o exemplo
Também para a aplicação cliente, temos que escolher corretamente os valores no arquivo.properties da aplicação. Em uma configuração comum, elas corresponderiam exatamente às usadas no lado do servidor.
Isso deve ser suficiente para demonstrar a chamada remota por meio deApache AMQ. Então, vamos primeiro iniciarApacheMQ, em seguida, o aplicativo do servidor e, finalmente, o aplicativo cliente que invocará o serviço remoto
6. Conclusão
Neste tutorial rápido, vimos como poderíamos usarSpring Remoting para fornecerRPC no topo de um sistemaJMS comoAMQ.
O Spring Remoting continua demonstrando como é fácil configurar chamadas assíncronas, independentemente do canal subjacente, rapidamente.
Como de costume, você encontrará as fontesover on GitHub.