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:

Padrão de Tópicos RabbitMQ

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:

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.