Tipo de intercambio RabbitMQ (Directo, Tema, Fanout, Encabezados) y modo de envío / recepción de mensajes

1. Tipo de intercambio RabbitMQ

Hay cuatro tipos de intercambios comúnmente usados ​​por RabbitMQ: Directo, Tema, Fanout y Encabezados. El protocolo AMQP también menciona otros dos tipos: Sistema y Personalizado, que no se describen aquí. Estos cuatro tipos se explican a continuación uno por uno.

1.1 Tipo directo

El intercambio de tipo Direct tiene reglas de enrutamiento muy simples, enrutará el mensaje a aquellas colas cuya BindingKey y RoutingKey coincidan exactamente.

Direct Exchange es el modo de intercambio predeterminado de RabbitMQ y también es el modo más simple. Encuentra la cola basándose en la coincidencia exacta de RoutingKey.

1.2 Tipo de tema

Como se mencionó anteriormente, las reglas de enrutamiento del conmutador de tipo directo deben coincidir completamente con BindingKey y RoutingKey, pero este método de coincidencia estricto no puede satisfacer las necesidades comerciales reales en muchos casos. El intercambio de tipo de tema se ha ampliado en las reglas de coincidencia. Es similar al tipo de intercambio directo. También enruta el mensaje a la cola que coincide con BindingKey y RoutingKey, pero las reglas de coincidencia aquí son algo diferentes. Concuerda:

(1) RoutingKey es una cadena separada por un punto "." (Cada cadena independiente separada por un punto "." Se llama una palabra), como: com.rabbitmq.client, java.util. Concurrent, com.hidden. cliente;

(2) BindingKey y RoutingKey también son cadenas separadas por puntos ".";

(3) Puede haber dos cadenas especiales, el asterisco "*" y el signo de almohadilla "#" en BindingKey, que se utilizan para la coincidencia aproximada, donde el asterisco "*" se usa para hacer coincidir una palabra y el signo de almohadilla "#" se utiliza para hacer coincidir varias palabras regulares (0 o más palabras);

1.3 Tipo de fanout

El modo de difusión de mensajes es difundir el mensaje a todas las colas vinculadas a él, independientemente del valor de RoutingKey (sin clave de canalización o modo de enrutamiento). Si se establece RoutingKey, RoutingKey aún se ignora.

1.4 Tipo de encabezados

El tipo de Intercambiador de encabezados no se basa en las reglas de coincidencia de la clave de enrutamiento para enrutar el mensaje, sino que coincide con el atributo de encabezados en el contenido del mensaje enviado. Desarrolle un conjunto de pares clave-valor al vincular la cola y el intercambio. Al enviar un mensaje al intercambio, RabbitMQ obtendrá los encabezados del mensaje (también en forma de un par clave-valor) y comparará si el valor clave pares coinciden exactamente El par clave-valor especificado cuando la cola y el intercambio están vinculados, si coinciden exactamente, el mensaje se enrutará a esta cola; de lo contrario, no se enrutará a esta cola. El rendimiento del conmutador de tipo Headers será pobre y no es práctico, básicamente no verá su existencia.

 

2. Modo de envío / recepción de mensajes de RabbitMQ

A continuación, se explicará el modo de envío / recepción de RabbitMQ a través de ejemplos. Primero, debe crear dos proyectos SpringBoot e integrar los clientes de RabbitMQ.

(1) Cree el primer proyecto SpringBoot (proyecto de envío de mensajes de rabbitmq-provider), la estructura del proyecto es la siguiente:

En el archivo de información de configuración pom.xml, agregue los archivos dependientes relacionados:

<!-- AMQP客户端 -->
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-amqp</artifactId>
    <version>2.4.1</version>
</dependency>

Configure el servicio RabbitMQ en el archivo de configuración application.yml:

spring:
  # 项目名称
  application:
    name: rabbitmq-provider
  # RabbitMQ服务配置
  rabbitmq:
    host: 127.0.0.1
    port: 5672
    username: guest
    password: guest

(2) Cree el segundo proyecto SpringBoot (proyecto de recepción de mensajes rabbitmq-consumer), la estructura del proyecto es la siguiente:

En el archivo de información de configuración pom.xml, agregue los archivos dependientes relacionados:

<!-- AMQP客户端 -->
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-amqp</artifactId>
    <version>2.4.1</version>
</dependency>

Configure el servicio RabbitMQ en el archivo de configuración application.yml:

spring:
  # 项目名称
  application:
    name: rabbitmq-consumer
  # RabbitMQ服务配置
  rabbitmq:
    host: 127.0.0.1
    port: 5672
    username: guest
    password: guest

2.1 Implementar colas de envío y recepción

Utilice el modo directo para implementar colas de envío y recepción de mensajes.

(1) Configurar la cola

En rabbitmq-provider (proyecto de envío de mensajes), configure el nombre de la cola y transfiera la cola a la administración de IoC, el código es el siguiente:

package com.pjb.config;

import org.springframework.amqp.core.*;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

/**
 * RabbitMQ配置类
 * @author pan_junbiao
 **/
@Configuration
public class DirectRabbitMqConfig
{
    public static final String DIRECT_QUEUE_NAME = "direct_queue_name"; //队列名称
    public static final String DIRECT_EXCHANGE_NAME = "direct_exchange_name"; //交换器名称
    public static final String DIRECT_ROUTING_KEY = "direct_routing_key"; //路由键

    /**
     * 队列
     */
    @Bean
    public Queue directQueue()
    {
        /**
         * 创建队列,参数说明:
         * String name:队列名称。
         * boolean durable:设置是否持久化,默认是 false。durable 设置为 true 表示持久化,反之是非持久化。
         * 持久化的队列会存盘,在服务器重启的时候不会丢失相关信息。
         * boolean exclusive:设置是否排他,默认也是 false。为 true 则设置队列为排他。
         * boolean autoDelete:设置是否自动删除,为 true 则设置队列为自动删除,
         * 当没有生产者或者消费者使用此队列,该队列会自动删除。
         * Map<String, Object> arguments:设置队列的其他一些参数。
         */
        return new Queue(DIRECT_QUEUE_NAME, true, false, false, null);
    }

    /**
     * Direct交换器
     */
    @Bean
    public DirectExchange directExchange()
    {
        /**
         * 创建交换器,参数说明:
         * String name:交换器名称
         * boolean durable:设置是否持久化,默认是 false。durable 设置为 true 表示持久化,反之是非持久化。
         * 持久化可以将交换器存盘,在服务器重启的时候不会丢失相关信息。
         * boolean autoDelete:设置是否自动删除,为 true 则设置队列为自动删除,
         */
        return new DirectExchange(DIRECT_EXCHANGE_NAME, true, false);
    }

    /**
     * 绑定
     */
    @Bean
    Binding bindingDirect(DirectExchange directExchange,Queue directQueue)
    {
        //将队列和交换机绑定, 并设置用于匹配键:routingKey
        return BindingBuilder.bind(directQueue).to(directExchange).with(DIRECT_ROUTING_KEY);
    }
}

(2) Crea un remitente

En rabbitmq-provider (proyecto de envío de mensajes), cree un remitente y utilice el método rabbitTemplate.convertAndSend () para enviar el mensaje. El código es el siguiente:

package com.pjb;

import com.pjb.config.DirectRabbitMqConfig;
import org.junit.jupiter.api.Test;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;

import java.util.HashMap;
import java.util.Map;

/**
 * RabbitMQ测试类
 * @author pan_junbiao
 **/
@SpringBootTest
public class DirectRabbitMqTest
{
    @Autowired
    RabbitTemplate rabbitTemplate;

    @Test
    public void sendDirectMessage()
    {
        //创建用户信息
        Map<String, Object> userMap = new HashMap<>();
        userMap.put("userId", "1");
        userMap.put("userName", "pan_junbiao的博客");
        userMap.put("blogUrl", "https://blog.csdn.net/pan_junbiao");
        userMap.put("userRemark", "您好,欢迎访问 pan_junbiao的博客");

        /**
         * 发送消息,参数说明:
         * String exchange:交换器名称。
         * String routingKey:路由键。
         * Object object:发送内容。
         */
        rabbitTemplate.convertAndSend(DirectRabbitMqConfig.DIRECT_EXCHANGE_NAME, DirectRabbitMqConfig.DIRECT_ROUTING_KEY, userMap);
        System.out.println("消息发送成功!");
    }
}

(3) Crear receptor

En rabbitmq-consumer (proyecto de recepción de mensajes), cree un receptor. Tenga en cuenta que el nombre de la cola del remitente y del receptor debe ser el mismo, de lo contrario, el mensaje no se puede recibir. el código se muestra a continuación:

package com.pjb.receiver;

import org.springframework.amqp.rabbit.annotation.RabbitHandler;
import org.springframework.amqp.rabbit.annotation.RabbitListener;
import org.springframework.stereotype.Component;
import java.util.Map;

/**
 * 接收者
 * @author pan_junbiao
 **/
@Component
@RabbitListener(queues="direct_queue_name")
public class DirectReceiver
{
    @RabbitHandler
    public void process(Map message)
    {
        System.out.println("接收者收到消息:");
        System.out.println("用户编号:" + message.get("userId"));
        System.out.println("用户名称:" + message.get("userName"));
        System.out.println("博客地址:" + message.get("blogUrl"));
        System.out.println("博客信息:" + message.get("userRemark"));
    }
}

Ejecute el método de envío en rabbitmq-provider (proyecto de envío de mensajes) y luego ejecute rabbitmq-consumer (proyecto de recepción de mensajes), verá el resultado de la ejecución desde la consola.

Resultados del:

 

2.2 Implementación de recibir múltiples temas con un receptor

El modo de tema es el modo más flexible en RabbitMQ, que puede enlazar libremente diferentes colas de acuerdo con RoutingKey.

(1) Configurar el modo de tema

En rabbitmq-provider (proyecto de envío de mensajes), configure la cola para procesar mensajes, el código es el siguiente:

package com.pjb.config;

import org.springframework.amqp.core.Binding;
import org.springframework.amqp.core.BindingBuilder;
import org.springframework.amqp.core.Queue;
import org.springframework.amqp.core.TopicExchange;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

/**
 * RabbitMQ配置类
 * @author pan_junbiao
 **/
@Configuration
public class TopicRabbitMqConfig
{
    public static final String TOPIC_QUEUE_NAME_A = "topic_queue_name_a"; //队列名称A
    public static final String TOPIC_QUEUE_NAME_B = "topic_queue_name_b"; //队列名称B
    public static final String TOPIC_EXCHANGE_NAME = "topic_exchange_name"; //交换器名称

    /**
     * 队列A
     */
    @Bean
    public Queue topicQueueA()
    {
        /**
         * 创建队列,参数说明:
         * String name:队列名称。
         * boolean durable:设置是否持久化,默认是 false。durable 设置为 true 表示持久化,反之是非持久化。
         * 持久化的队列会存盘,在服务器重启的时候不会丢失相关信息。
         * boolean exclusive:设置是否排他,默认也是 false。为 true 则设置队列为排他。
         * boolean autoDelete:设置是否自动删除,为 true 则设置队列为自动删除,
         * 当没有生产者或者消费者使用此队列,该队列会自动删除。
         * Map<String, Object> arguments:设置队列的其他一些参数。
         */
        return new Queue(TOPIC_QUEUE_NAME_A, true);
    }

    /**
     * 队列B
     */
    @Bean
    public Queue topicQueueB()
    {
        /**
         * 创建队列,参数说明:
         * String name:队列名称。
         * boolean durable:设置是否持久化,默认是 false。durable 设置为 true 表示持久化,反之是非持久化。
         * 持久化的队列会存盘,在服务器重启的时候不会丢失相关信息。
         * boolean exclusive:设置是否排他,默认也是 false。为 true 则设置队列为排他。
         * boolean autoDelete:设置是否自动删除,为 true 则设置队列为自动删除,
         * 当没有生产者或者消费者使用此队列,该队列会自动删除。
         * Map<String, Object> arguments:设置队列的其他一些参数。
         */
        return new Queue(TOPIC_QUEUE_NAME_B, true);
    }

    /**
     * Topic交换器
     */
    @Bean
    TopicExchange exchange()
    {
        /**
         * 创建交换器,参数说明:
         * String name:交换器名称
         * boolean durable:设置是否持久化,默认是 false。durable 设置为 true 表示持久化,反之是非持久化。
         * 持久化可以将交换器存盘,在服务器重启的时候不会丢失相关信息。
         * boolean autoDelete:设置是否自动删除,为 true 则设置队列为自动删除,
         */
        return new TopicExchange(TOPIC_EXCHANGE_NAME, true, false);
    }

    /**
     * 绑定1
     */
    @Bean
    Binding bindingExchangeMessage1(Queue topicQueueA, TopicExchange exchange)
    {
        //将队列和交换机绑定, 并设置用于匹配键:routingKey
        return BindingBuilder.bind(topicQueueA).to(exchange).with("topic.routingKey.a");
    }

    /**
     * 绑定2
     */
    @Bean
    Binding bindingExchangeMessage2(Queue topicQueueB, TopicExchange exchange)
    {
        //将队列和交换机绑定, 并设置用于匹配键:routingKey
        return BindingBuilder.bind(topicQueueB).to(exchange).with("topic.routingKey.#");
    }
}

(2) Crea un remitente

En rabbitmq-provider (proyecto de envío de mensajes), cree un remitente y pruebe el efecto enviando diferentes RoutingKeys. el código se muestra a continuación:

package com.pjb;

import com.pjb.config.TopicRabbitMqConfig;
import org.junit.jupiter.api.Test;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;

/**
 * RabbitMQ测试类
 * @author pan_junbiao
 **/
@SpringBootTest
public class TopicRabbitMqTest
{
    @Autowired
    private RabbitTemplate rabbitTemplate;

    @Test
    public void sendTopicMessage1()
    {
        String context = "pan_junbiao的博客_01";
        System.out.println("Sender:" + context);
        this.rabbitTemplate.convertAndSend(TopicRabbitMqConfig.TOPIC_EXCHANGE_NAME,"topic.routingKey.cc",context);
    }

    @Test
    public void sendTopicMessage2()
    {
        String context = "pan_junbiao的博客_02";
        System.out.println("Sender:" + context);
        this.rabbitTemplate.convertAndSend(TopicRabbitMqConfig.TOPIC_EXCHANGE_NAME,"topic.routingKey.a",context);
    }

    @Test
    public void sendTopicMessage3()
    {
        String context = "pan_junbiao的博客_03";
        System.out.println("Sender:" + context);
        this.rabbitTemplate.convertAndSend(TopicRabbitMqConfig.TOPIC_EXCHANGE_NAME,"topic.routingKey.pjb",context);
    }
}

(3) Crear receptor

En rabbitmq-consumer (proyecto de recepción de mensajes), cree el receptor A. el código se muestra a continuación:

package com.pjb.receiver;

import org.springframework.amqp.rabbit.annotation.RabbitHandler;
import org.springframework.amqp.rabbit.annotation.RabbitListener;
import org.springframework.stereotype.Component;

/**
 * 接收者
 * @author pan_junbiao
 **/
@Component
@RabbitListener(queues = "topic_queue_name_a")
public class TopicReceiverA
{
    @RabbitHandler
    public void process(String msg)
    {
        System.out.println("Topic ReceiverA:" + msg);
    }
}

En rabbitmq-consumer (proyecto de recepción de mensajes), cree el receptor B. el código se muestra a continuación:

package com.pjb.receiver;

import org.springframework.amqp.rabbit.annotation.RabbitHandler;
import org.springframework.amqp.rabbit.annotation.RabbitListener;
import org.springframework.stereotype.Component;

/**
 * 接收者
 * @author pan_junbiao
 **/
@Component
@RabbitListener(queues = "topic_queue_name_b")
public class TopicReceiverB
{
    @RabbitHandler
    public void process(String msg)
    {
        System.out.println("Topic ReceiverB:" + msg);
    }
}

Ejecute el método de envío en rabbitmq-provider (proyecto de envío de mensajes) respectivamente, y luego ejecute rabbitmq-consumer (proyecto de recepción de mensajes), y verá el resultado de la ejecución desde la consola.

Resultado de ejecución 1:

Resultado de ejecución 2:

Resultado de implementación 3:

 

2.3 Realice el modo de transmisión

Los interruptores de tipo Fanout pueden implementar el modo de transmisión. En este modo, todas las colas vinculadas al intercambio pueden recibir este mensaje.

(1) Configurar el tipo de Fanout

En rabbitmq-provider (proyecto de envío de mensajes), configure el objeto del modo de transmisión. el código se muestra a continuación:

package com.pjb.config;

import org.springframework.amqp.core.Binding;
import org.springframework.amqp.core.BindingBuilder;
import org.springframework.amqp.core.FanoutExchange;
import org.springframework.amqp.core.Queue;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

/**
 * RabbitMQ配置类
 * @author pan_junbiao
 **/
@Configuration
public class FanoutRabbitMqConfig
{
    public static final String FANOUT_QUEUE_NAME_A = "fanout_queue_name_a"; //队列名称
    public static final String FANOUT_QUEUE_NAME_B = "fanout_queue_name_b"; //队列名称
    public static final String FANOUT_QUEUE_NAME_C = "fanout_queue_name_c"; //队列名称
    public static final String FANOUT_EXCHANGE_NAME = "fanout_exchange_name"; //交换器名称

    @Bean
    public Queue fanoutQueueA()
    {
        return new Queue(FANOUT_QUEUE_NAME_A, true);
    }

    @Bean
    public Queue fanoutQueueB()
    {
        return new Queue(FANOUT_QUEUE_NAME_B, true);
    }

    @Bean
    public Queue fanoutQueueC()
    {
        return new Queue(FANOUT_QUEUE_NAME_C, true);
    }

    @Bean
    FanoutExchange fanoutExchange()
    {
        return new FanoutExchange(FANOUT_EXCHANGE_NAME);
    }

    @Bean
    Binding bindingExchangeA(Queue fanoutQueueA, FanoutExchange fanoutExchange)
    {
        return BindingBuilder.bind(fanoutQueueA).to(fanoutExchange);
    }

    @Bean
    Binding bindingExchangeB(Queue fanoutQueueB, FanoutExchange fanoutExchange)
    {
        return BindingBuilder.bind(fanoutQueueB).to(fanoutExchange);
    }

    @Bean
    Binding bindingExchangeC(Queue fanoutQueueC, FanoutExchange fanoutExchange)
    {
        return BindingBuilder.bind(fanoutQueueC).to(fanoutExchange);
    }
}

(2) Crea un remitente

En rabbitmq-provider (proyecto de envío de mensajes), cree un remitente, el código es el siguiente:

package com.pjb;

import com.pjb.config.FanoutRabbitMqConfig;
import org.junit.jupiter.api.Test;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;

/**
 * RabbitMQ测试类
 * @author pan_junbiao
 **/
@SpringBootTest
public class FanoutRabbitMqTest
{
    @Autowired
    private RabbitTemplate rabbitTemplate;

    @Test
    public void sendFanoutMessage()
    {
        String context = "您好,欢迎访问 pan_junbiao的博客";
        System.out.println("Sender:" + context);
        this.rabbitTemplate.convertAndSend(FanoutRabbitMqConfig.FANOUT_EXCHANGE_NAME, "", context);
    }
}

(3) Crear receptor

En rabbitmq-consumer (proyecto de recepción de mensajes), cree el receptor A. el código se muestra a continuación:

package com.pjb.receiver;

import org.springframework.amqp.rabbit.annotation.RabbitHandler;
import org.springframework.amqp.rabbit.annotation.RabbitListener;
import org.springframework.stereotype.Component;

/**
 * 接收者
 * @author pan_junbiao
 **/
@Component
@RabbitListener(queues = "fanout_queue_name_a")
public class FanoutReceiverA
{
    @RabbitHandler
    public void process(String message)
    {
        System.out.println("Fanout ReceiverA:" + message);
    }
}

En rabbitmq-consumer (proyecto de recepción de mensajes), cree el receptor B. el código se muestra a continuación:

package com.pjb.receiver;

import org.springframework.amqp.rabbit.annotation.RabbitHandler;
import org.springframework.amqp.rabbit.annotation.RabbitListener;
import org.springframework.stereotype.Component;

/**
 * 接收者
 * @author pan_junbiao
 **/
@Component
@RabbitListener(queues = "fanout_queue_name_b")
public class FanoutReceiverB
{
    @RabbitHandler
    public void process(String message)
    {
        System.out.println("Fanout ReceiverB:" + message);
    }
}

 En rabbitmq-consumer (proyecto de recepción de mensajes), cree el receptor C. el código se muestra a continuación:

package com.pjb.receiver;

import org.springframework.amqp.rabbit.annotation.RabbitHandler;
import org.springframework.amqp.rabbit.annotation.RabbitListener;
import org.springframework.stereotype.Component;

/**
 * 接收者
 * @author pan_junbiao
 **/
@Component
@RabbitListener(queues = "fanout_queue_name_c")
public class FanoutReceiverC
{
    @RabbitHandler
    public void process(String message)
    {
        System.out.println("Fanout ReceiverC:" + message);
    }
}

Ejecute el método de envío en rabbitmq-provider (proyecto de envío de mensajes) y luego ejecute rabbitmq-consumer (proyecto de recepción de mensajes), verá el resultado de la ejecución desde la consola.

Resultados del:

 

Supongo que te gusta

Origin blog.csdn.net/pan_junbiao/article/details/112838589
Recomendado
Clasificación