Il modello di routing dei temi RabbitMQ in Java, utilizzando il tipo di scambio TopicExchange, si differenzia dal modello di routing (Direct) nel supportare la corrispondenza approssimativa dei parametri di routing. Poiché la corrispondenza del routing è più flessibile, è un modello più comunemente utilizzato. L'architettura è illustrata nel seguente diagramma:

Modello di routing dei temi RabbitMQ

Suggerimento: Indipendentemente dal pattern di lavoro di RabbitMQ utilizzato, la differenza sta nel tipo di scambio utilizzato e nei parametri di routing.

1. Tutorial Preliminare

Si prega di leggere prima le seguenti sezioni per comprendere le conoscenze rilevanti:

2. Definizione dello scambio dei temi

In Spring AMQP, la classe corrispondente allo scambio diretto è TopicExchange. Definiamo lo scambio attraverso una classe di configurazione di 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() {
        // Definire lo scambio
        // Il parametro è il nome dello scambio, che deve essere unico
        return new TopicExchange("tizi365.topic");
    }
}

Suggerimento: Sia i produttori che i consumatori di messaggi hanno bisogno dello scambio.

3. Invio dei messaggi

Inviamo messaggi allo scambio e lo scambio consegna i messaggi alle code corrispondenti in base alle regole di routing.

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;

    // A fini dimostrativi, qui viene utilizzato un compito pianificato per inviare un messaggio ogni secondo
    @Scheduled(fixedDelay = 1000, initialDelay = 1000)
    public void send() {
        // Contenuto del messaggio
        String message = "Ciao Mondo!";
        // Invia messaggio
        // Il primo parametro è il nome dello scambio
        // Il secondo parametro è la chiave di routing. Lo scambio dei temi consegna i messaggi alle code che corrispondono alla chiave di routing
        // Il terzo parametro è il contenuto del messaggio, supportando qualsiasi tipo purché possa essere serializzato
        template.convertAndSend(topic.getName(), "www.tizi365.com", message);
        System.out.println("Messaggio inviato: '" + message + "'");
    }
}

Suggerimento: Presta attenzione al secondo parametro "www.tizi365.com" nel metodo convertAndSend, poiché è un parametro cruciale.

4. Ricezione dei messaggi

4.1 Definire Code e Collegare Exchange

Per consumare messaggi dalle code, è necessario prima definire una coda e poi collegarla allo scambio di destinazione. Di seguito vengono definite due code e collegate allo stesso exchange.

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() {
        // Definire lo scambio
        // Il parametro è il nome dello scambio, che deve essere univoco
        return new TopicExchange("tizi365.topic");
    }

    @Bean
    public Queue queue1() {
        // Definire la coda 1
        return new Queue("tizi365.topic.queue1");
    }

    @Bean
    public Queue queue2() {
        // Definire la coda 2
        return new Queue("tizi365.topic.queue2");
    }

    @Bean
    public Binding binding1(TopicExchange topic, Queue queue1) {
        // Definire una relazione di collegamento, collegando la coda 1 allo scambio di argomento con una chiave di instradamento di: *.tizi365.com
        return BindingBuilder.bind(queue1).to(topic).with("*.tizi365.com");
    }

    @Bean
    public Binding binding2(TopicExchange topic, Queue queue2) {
        // Definire una relazione di collegamento, collegando la coda 2 allo scambio di argomento con una chiave di instradamento di: *.baidu.com
        return BindingBuilder.bind(queue2).to(topic).with("*.baidu.com");
    }
}

Suggerimento: Quando si collegano la coda 1 e la coda 2 allo scambio, le chiavi di instradamento impostate utilizzano entrambe il * (asterisco) jolly, che corrisponde a una singola parola. Se cambiate a # (cancelletto), corrisponderebbe a più parole.

4.2 Definire Ascoltatori di Code

Definire gli ascoltatori dei messaggi utilizzando l'annotazione RabbitListener per consumare messaggi da code specifiche.

package com.tizi365.rabbitmq.listener;

import org.springframework.amqp.rabbit.annotation.*;
import org.springframework.stereotype.Component;

// Consentire a Spring di gestire la classe corrente
@Component
public class DemoListener {
    // Definire un ascoltatore, specificando a quale coda ascoltare attraverso il parametro delle code
    @RabbitListener(queues = "tizi365.topic.queue1")
    public void receive1(String msg) {
        System.out.println("Ricevuto messaggio dalla coda 1: " + msg);
    }

    // Definire un ascoltatore, specificando a quale coda ascoltare attraverso il parametro delle code
    @RabbitListener(queues = "tizi365.topic.queue2")
    public void receive2(String msg) {
        System.out.println("Ricevuto messaggio dalla coda 2: " + msg);
    }
}

Poiché solo la coda 1 ha una chiave di instradamento di *.tizi365.com quando viene collegata allo scambio, corrisponderà ai messaggi con la chiave di instradamento (www.tizi365.com). Pertanto, solo la coda 1 sarà in grado di ricevere i messaggi, mentre la coda 2 non ne riceverà a causa di una chiave di instradamento non corrispondente.