• JP

Spring Boot e ActiveMQ

Apache ActiveMQ é um servidor de mensageria de código aberto utilizado por grandes players do mercado que utilizam arquiteturas open-source. Mas qual é a proposta do ActiveMQ?


Antes de entender o que é o ActiveMQ, temos que pensar em problemas comuns em aplicações que precisam escalar e integrar melhor seus serviços. Hoje o fluxo de informações trafegadas é infinitamente maior que 10 anos atrás e é quase impossível mensurar capacidade em termos de escalabilidade que uma aplicação pode suportar.


Para entendermos melhor, vamos imaginar que você foi contratado para projetar uma arquitetura de um e-commerce que fará vendas de ingressos dos jogos da campeonato brasileiro. Como sempre você tem pouco tempo para pensar uma arquitetura. A primeira ideia é simples e rápida, o resultado é este desenho.



Levando em conta a quantidade de acessos e requisições por segundo, você acha uma arquitetura resiliente? Será que o banco de dados escala? Será que o banco suporta multi-acessos? E se o banco por algum motivo cair, a compra será perdida? Podemos melhorar um pouco mais essa arquitetura deixando ela um pouco mais profissional e resiliente. Vamos lá.



Vamos entender este último desenho. Agora, ao efetuar um pedido de compra os pedidos são enviados para um servidor de mensagens (Fila). A ideia da Fila é basicamente um serviço capaz de alocar mensagens. Normalmente são textos ou texto em formato Json. Neste desenho podemos dizer que a Fila aloca dados do cliente, quantidade de ingressos, valores e etc.


E por fim, existe uma aplicação que faz todo o gerenciamento dos pedidos/compras. Esta aplicação lê/remove as mensagens da Fila podendo fazer validações antes de gravar no banco de dados.


Agora, vamos supor que um dos requisitos é para cada venda, o cliente deve receber uma nota fiscal do ingresso. Como a nova arquitetura está bem desacoplada, ficou mais fácil "plugar" uma nova aplicação para fazer este trabalho. Daí você pensou em um novo desenho, segue:



Agora a aplicação que gerencia as compras, além de gravar a venda após recuperar as mensagens na fila 1, ela envia uma mensagem também para a fila 2, onde alocará as notas fiscais dos clientes. E uma nova aplicação que gerencia as notas fiscais recupera estas mensagens e grava em uma base especifica para o setor financeiro.


Mas quais os benefícios dessa nova arquitetura? A arquitetura está mais resiliente, assíncrona e tolerável a falhas, pois caso umas das aplicações por algum motivo falhe, a mensagem retorna para a fila até o reestabelecimento das aplicações. E por fim, facilita a integração de novas aplicações.


E o ActiveMQ? O que ele tem haver com isso? O ActiveMQ é o serviço que provê o servidor de mensagens. No desenho, ele seria os servidores de mensagens (Filas).


Lembrando que os desenhos foram uma forma de abrir a cabeça quanto a utilidade de Filas.

Para entender melhor ainda, vamos apresentar um exemplo na prática de como configurar e utilizar o ActiveMQ com Spring Boot e JMS.


Criando o projeto


Acesse o https://start.spring.io para criar o projeto e escolher as dependências.

Preencha os campos e selecione as 2 dependências (ActiveMQ 5 e Spring Web) conforme a imagem. Gere o arquivo e importe para o seu projeto.


pom.xml Completo

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
   xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
   <modelVersion>4.0.0</modelVersion>
   <parent>
      <groupId>org.springframework.boot</groupId>
      <artifactId>spring-boot-starter-parent</artifactId>
      <version>2.4.2</version>
      <relativePath/> <!-- lookup parent from repository -->
   </parent>
   <groupId>com.spring.active.mq</groupId>
   <artifactId>spring-boot-active-mq</artifactId>
   <version>0.0.1-SNAPSHOT</version>
   <name>spring-boot-active-mq</name>
   <description>Demo project for Spring Boot</description>
   <properties>
      <java.version>1.8</java.version>
   </properties>
   
   <dependencies>
      <dependency>
         <groupId>org.springframework.boot</groupId>
         <artifactId>spring-boot-starter-activemq</artifactId>
      </dependency>
      <dependency>
         <groupId> org.springframework.boot</groupId>
         <artifactId>spring-boot-starter-web</artifactId>
      </dependency>
      <dependency>
         <groupId>org.springframework.boot</groupId>
         <artifactId>spring-boot-starter-test</artifactId>
         <scope>test</scope>
      </dependency>
   </dependencies>

   <build>
      <plugins>
         <plugin>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-maven-plugin</artifactId>
         </plugin>
      </plugins>
   </build>
</project>

Instalando o ActiveMQ


Vamos fazer o download do ActiveMQ para que o processo fique mais transparente. Mas também existe a possibilidade em utilizar a versão embutida do Spring Boot, mas dessa vez vamos apresentar da forma mais tradicional. Para este exemplo, vamos utilizar a versão clássica do ActiveMQ.


Download: https://activemq.apache.org/components/classic/download/


Faça a instalação conforme seu sistema operacional: https://activemq.apache.org/getting-started


Após a instalação, inicie o servidor conforme a documentação.


Preenchendo o arquivo application.properties


Na aplicação Spring-Boot criada, preencha o arquivo application.properties

spring.activemq.broker-url=tcp://127.0.0.1:61616
spring.activemq.user=admin
spring.activemq.password=admin
  1. A primeira linha configura a URL do servidor de mensagens

  2. A segunda linha e a subsequente são os dados de autenticação

Classe Ticket

public class Ticket {

    private String name;
    private Double price;
    private int quantity;

    public Ticket(){}

    public Ticket(String name, Double price, int quantity){
        this.name = name;
        this.price = price;
        this.quantity = quantity;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public Double getPrice() {
        return price;
    }

    public void setPrice(Double price) {
        this.price = price;
    }

    public int getQuantity() {
        return quantity;
    }

    public void setQuantity(int quantity) {
        this.quantity = quantity;
    }

    @Override
    public String toString() {
        return String.format("Compra de ingresso -> " +
                "Name=%s, Price=%s, Quantity=%s}",
                getName(), getPrice(), getQuantity());
    }
}

Na classe SpringBootActiveMqApplication já criada anteriormente pelo gerador, faça a seguinte alteração.

@SpringBootApplication
@EnableJms
public class SpringBootActiveMqApplication {

   public static void main(String[] args) {
      SpringApplication.run(SpringBootActiveMqApplication.class, args);
   }

   @Bean
   public JmsListenerContainerFactory<?> defaultFactory(
           ConnectionFactory connectionFactory,
            DefaultJmsListenerContainerFactoryConfigurer configurer) {
       
      DefaultJmsListenerContainerFactory factory =
                new DefaultJmsListenerContainerFactory();
      configurer.configure(factory, connectionFactory);
      return factory;
   }

   @Bean
   public MessageConverter jacksonJmsMessageConverter() {
      MappingJackson2MessageConverter converter =
                new MappingJackson2MessageConverter();
      converter.setTargetType(MessageType.TEXT);
      converter.setTypeIdPropertyName("_type");
      return converter;
   }
}
  1. A anotação @EnableJms é o mecanismo responsável por ativar o JMS.

  2. O método defaultFactory configura e registra a factory para conectar as filas utilizando JMS.

  3. E por fim, o método jacksonJmsMessageConverter faz as conversões das mensagens trafegadas de JSON para o tipo que será passado no JmsTemplate que veremos em breve. Todos estes métodos utilizam a anotação @Bean. Métodos anotados com @Bean são gerenciados pelo contêiner do Spring.

Classe TicketController

package com.spring.active.mq.springbootactivemq.Controller;

import com.spring.active.mq.springbootactivemq.pojo.Ticket;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.MediaType;
import org.springframework.jms.core.JmsTemplate;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RestController;

@RestController
public class TicketController {

    @Autowired
    private JmsTemplate jmsTemplate;

    @PostMapping(value = "/buy", 
    consumes =  MediaType.APPLICATION_JSON_VALUE)
    public void buyTicket(@RequestBody Ticket ticket){
        jmsTemplate.convertAndSend("compra_queue",
                new Ticket(ticket.getName(),
                        ticket.getPrice(),
                        ticket.getQuantity()));
    }
}

Na classe TicketController, criamos o método chamado buyTicket que será responsável por enviar as mensagens para a fila chamada compra_queue através de uma requisição POST. Neste método utilizamos um objeto do tipo JmsTemplate que possibilita a conversão do objeto e o envio para a fila utilizando JMS.


Classe EventListener

package com.spring.active.mq.springbootactivemq.listener;
import com.spring.active.mq.springbootactivemq.pojo.Ticket;
import org.springframework.jms.annotation.JmsListener;
import org.springframework.stereotype.Component;


@Component
public class EventListener {
    @JmsListener(destination = "compra_queue",
            containerFactory = "defaultFactory")
    public void receiveMessage(Ticket ticket) {
        System.out.println("Mensagem da fila:" + ticket);
    }
}

A classe EventListener é uma espécie de "ouvinte". A anotação @JmsListener define esta característica de ouvinte. Nesta mesma anotação é possível configurar o nome da fila que será "ouvida" pelo método.

Resumindo, todas a mensagens enviadas para a fila compra_queue serão recebidas por este método.


Acessando o serviço de Fila - ActiveMQ


Após a inicialização do serviço conforme a documentação, acesse o console do serviço através de um browser http://127.0.0.1:8161/

Criando a fila

Para criar a fila, clique na opção Queues na barra superior vermelha, conforme a imagem acima.

No campo Queue Name digite nome da fila compra_queue conforme imagem acima e clique no botão Create.

Pronto, fila criada!


Iniciando a aplicação


Via terminal, acesse o diretório do seu projeto e execute o comando Maven abaixo ou inicie via IDE

mvn spring-boot:run

Enviando mensagens


Vamos usar o Postman para o envio das mensagens, caso não tenha o Postman instalado, faça o download acessando este link https://www.postman.com/downloads/


Após a instalação, acesse o Postman e preencha os campos conforme a imagem

Conteúdo do Json

{"name":"Joao","price":2.0,"quantity":4}

Ao clicar no botão Send, acesse o console da aplicação e será possível visualizar a mensagem enviada e trafegada na fila.

Acesse novamente o console do ActiveMQ e será possível ver o registro da mensagem que foi enviada para a fila.


A coluna Number of Consumers é a quantidade de consumidores da fila, que no caso é realmente 1. A coluna Messages Enqueued mostra a quantidade de mensagens que foram enviadas e por fim, a coluna Messages Dequeued é o número de mensagens que foram removidas da fila.


Então é isso, espero que tenha te ajudado. Até mais!



Posts recentes

Ver tudo