RabbitMQ exchange type (Direct, Topic, Fanout, Headers) and message sending/receiving mode

1. RabbitMQ exchange type

There are four types of exchanges commonly used by RabbitMQ: Direct, Topic, Fanout, and Headers. The AMQP protocol also mentions two other types: System and Custom, which are not described here. These four types are explained below one by one.

1.1 Direct type

The Direct type exchange has very simple routing rules, it will route the message to those queues whose BindingKey and RoutingKey exactly match.

Direct Exchange is the default exchange mode of RabbitMQ, and it is also the simplest mode. It finds the queue based on the exact match of the RoutingKey.

1.2 Topic type

As mentioned above, the Direct type switch routing rules are to completely match BindingKey and RoutingKey, but this strict matching method cannot meet actual business needs in many cases. The Topic type exchange has been extended in the matching rules. It is similar to the Direct type of exchange. It also routes the message to the queue that matches the BindingKey and RoutingKey, but the matching rules here are somewhat different. It agrees:

(1) RoutingKey is a string separated by a dot "." (each independent string separated by a dot "." is called a word), such as: com.rabbitmq.client, java.util. concurrent, com.hidden.client;

(2) BindingKey and RoutingKey are also strings separated by dots ".";

(3) There can be two special strings asterisk "*" and pound sign "#" in the BindingKey, which are used for fuzzy matching, where the asterisk "*" is used to match a word, and the pound sign "#" is used to match Multiple regular words (0 or more words);

1.3 Fanout type

The mode of message broadcasting is to broadcast the message to all the queues bound to it, regardless of the value of the RoutingKey (no pipeline key or routing mode). If RoutingKey is set, RoutingKey is still ignored.

1.4 Headers type

The Exchanger of the Headers type does not rely on the matching rules of the routing key to route the message, but matches according to the headers attribute in the message content sent. Develop a set of key-value pairs when binding the queue and the exchange. When sending a message to the exchange, RabbitMQ will get the message headers (also in the form of a key-value pair), and compare whether the key-value pairs match exactly The key-value pair specified when the queue and the exchange are bound, if they match exactly, the message will be routed to this queue, otherwise it will not be routed to this queue. The performance of the Headers type switch will be poor, and it is not practical, basically you will not see its existence.

 

2. RabbitMQ message sending/receiving mode

The following will explain the sending/receiving mode of RabbitMQ through examples. First, you need to create two SpringBoot projects and integrate RabbitMQ clients.

(1) Create the first SpringBoot project (rabbitmq-provider message push project), the project structure is as follows:

In the pom.xml configuration information file, add related dependent files:

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

Configure the RabbitMQ service in the application.yml configuration file:

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

(2) Create the second SpringBoot project (rabbitmq-consumer message receiving project), the project structure is as follows:

In the pom.xml configuration information file, add related dependent files:

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

Configure the RabbitMQ service in the application.yml configuration file:

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

2.1 Implement sending and receiving queues

Use Direct mode to implement message sending and receiving queues.

(1) Configure the queue

In rabbitmq-provider (message push project), configure the name of the queue and transfer the queue to IoC management, the code is as follows:

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) Create a sender

In rabbitmq-provider (message push project), create a sender and use the rabbitTemplate.convertAndSend() method to send the message. The code is as follows:

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) Create receiver

In rabbitmq-consumer (message receiving project), create a receiver. Note that the Queue name of the sender and receiver must be the same, otherwise the message cannot be received. code show as below:

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"));
    }
}

Run the sending method in rabbitmq-provider (message push project), and then run rabbitmq-consumer (message receiving project), you will see the execution result from the console.

Results of the:

 

2.2 Implementation of receiving multiple topics with a receiver

Topic mode is the most flexible mode in RabbitMQ, which can freely bind different queues according to RoutingKey.

(1) Configure Topic mode

In rabbitmq-provider (message push project), configure the queue for processing messages, the code is as follows:

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) Create a sender

In rabbitmq-provider (message push project), create a sender and test the effect by sending different RoutingKeys. code show as below:

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) Create receiver

In rabbitmq-consumer (message receiving project), create receiver A. code show as below:

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);
    }
}

In rabbitmq-consumer (message receiving project), create receiver B. code show as below:

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);
    }
}

Run the sending method in rabbitmq-provider (message push project) respectively, and then run rabbitmq-consumer (message receiving project), and you will see the execution result from the console.

Execution result 1:

Execution result 2:

Implementation result 3:

 

2.3 Realize the broadcast mode

Fanout type switches can implement broadcast mode. In this mode, all queues bound to the exchange can receive this message.

(1) Configure Fanout type

In rabbitmq-provider (message push project), configure the object of the broadcast mode. code show as below:

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) Create a sender

In rabbitmq-provider (message push project), create a sender, the code is as follows:

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) Create receiver

In rabbitmq-consumer (message receiving project), create receiver A. code show as below:

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);
    }
}

In rabbitmq-consumer (message receiving project), create receiver B. code show as below:

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);
    }
}

 In rabbitmq-consumer (message receiving project), create receiver C. code show as below:

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);
    }
}

Run the sending method in rabbitmq-provider (message push project), and then run rabbitmq-consumer (message receiving project), you will see the execution result from the console.

Results of the:

 

Guess you like

Origin blog.csdn.net/pan_junbiao/article/details/112838589