O padrão de tópicos RabbitMQ em Java, utilizando o tipo TopicExchange, difere do padrão de roteamento (Direct) no sentido de que os parâmetros de roteamento suportam correspondência aproximada. Devido à sua flexibilidade, a correspondência de roteamento é um padrão mais comumente utilizado. A arquitetura é mostrada no diagrama a seguir:
Dica: Independentemente do padrão de trabalho RabbitMQ utilizado, a diferença está no tipo de exchange utilizado e nos parâmetros de roteamento.
1. Tutorial Prévio
Por favor, leia as seguintes seções primeiro para entender o conhecimento relevante:
- Conceitos Básicos do RabbitMQ
- Princípios do Padrão de Tópicos do RabbitMQ
- Início Rápido para Java com RabbitMQ (Leitura obrigatória, pois as seções subsequentes não repetirão o código, apenas mostrarão o código-chave)
- Seção Java RabbitMQ Publish-Subscribe Pattern (Leitura obrigatória, pois a sintaxe do código é quase a mesma, somente o tipo de exchange e os parâmetros de roteamento diferem)
2. Definindo a Troca de Tópicos
No Spring AMQP, a classe correspondente à troca direta é a TopicExchange. Definimos a troca através de uma classe de configuração do Spring Boot.
package com.tizi365.rabbitmq.config;
import org.springframework.amqp.core.*;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@Configuration
public class QueueConfig {
@Bean
public TopicExchange topic() {
// Definir a troca
// O parâmetro é o nome da troca, que deve ser único
return new TopicExchange("tizi365.topic");
}
}
Dica: Tanto os produtores quanto os consumidores de mensagens precisam da troca.
3. Enviando Mensagens
Enviamos mensagens para a troca, e a troca entrega as mensagens para as filas correspondentes com base nas regras de roteamento.
package com.tizi365.rabbitmq.service;
import org.springframework.amqp.core.DirectExchange;
import org.springframework.amqp.core.TopicExchange;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Service;
@Service
public class SendService {
@Autowired
private RabbitTemplate template;
@Autowired
private TopicExchange topic;
// Para fins de demonstração, uma tarefa agendada é usada aqui para enviar uma mensagem a cada segundo
@Scheduled(fixedDelay = 1000, initialDelay = 1000)
public void send() {
// Conteúdo da mensagem
String message = "Olá Mundo!";
// Enviar mensagem
// O primeiro parâmetro é o nome da troca
// O segundo parâmetro é a chave de roteamento. A troca de tópicos entrega as mensagens para filas que correspondem à chave de roteamento
// O terceiro parâmetro é o conteúdo da mensagem, suportando qualquer tipo, contanto que possa ser serializado
template.convertAndSend(topic.getName(), "www.tizi365.com", message);
System.out.println("Mensagem enviada: '" + message + "'");
}
}
Dica: Preste atenção ao segundo parâmetro "www.tizi365.com" no método convertAndSend, pois é um parâmetro crucial.
4. Recebendo Mensagens
4.1 Definir Filas e Vincular Trocas
Para consumir mensagens das filas, você precisa primeiro definir uma fila e depois vinculá-la à troca de destino. Abaixo, duas filas são definidas e vinculadas à mesma troca.
package com.tizi365.rabbitmq.config;
import org.springframework.amqp.core.*;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@Configuration
public class QueueConfig {
@Bean
public TopicExchange topic() {
// Define a troca
// O parâmetro é o nome da troca, que deve ser único
return new TopicExchange("tizi365.topic");
}
@Bean
public Queue queue1() {
// Definir fila 1
return new Queue("tizi365.topic.queue1");
}
@Bean
public Queue queue2() {
// Definir fila 2
return new Queue("tizi365.topic.queue2");
}
@Bean
public Binding binding1(TopicExchange topic, Queue queue1) {
// Definir um relacionamento de vinculação, vinculando a fila 1 à troca de tópicos com uma chave de roteamento de: *.tizi365.com
return BindingBuilder.bind(queue1).to(topic).with("*.tizi365.com");
}
@Bean
public Binding binding2(TopicExchange topic, Queue queue2) {
// Definir um relacionamento de vinculação, vinculando a fila 2 à troca de tópicos com uma chave de roteamento de: *.baidu.com
return BindingBuilder.bind(queue2).to(topic).with("*.baidu.com");
}
}
Dica: Ao vincular a fila 1 e a fila 2 à troca, as chaves de roteamento definidas estão usando o * (asterisco) curinga, que corresponde a uma única palavra. Se alterado para # (sustenido), corresponderia a várias palavras.
4.2 Definir Ouvintes de Filas
Defina ouvintes de mensagens usando a anotação RabbitListener para consumir mensagens de filas específicas.
package com.tizi365.rabbitmq.listener;
import org.springframework.amqp.rabbit.annotation.*;
import org.springframework.stereotype.Component;
// Permitir que o Spring gerencie a classe atual
@Component
public class DemoListener {
// Definir um ouvinte, especificando qual fila ouvir através do parâmetro de filas
@RabbitListener(queues = "tizi365.topic.queue1")
public void receive1(String msg) {
System.out.println("Recebeu mensagem da fila 1: " + msg);
}
// Definir um ouvinte, especificando qual fila ouvir através do parâmetro de filas
@RabbitListener(queues = "tizi365.topic.queue2")
public void receive2(String msg) {
System.out.println("Recebeu mensagem da fila 2: " + msg);
}
}
Como apenas a fila 1 possui uma chave de roteamento de *.tizi365.com ao se vincular à troca, ela corresponderá a mensagens com a chave de roteamento (www.tizi365.com). Portanto, apenas a fila 1 será capaz de receber mensagens, enquanto a fila 2 não receberá nenhuma devido à chave de roteamento não corresponder.