RabbitMQ交換タイプ(ダイレクト、トピック、ファンアウト、ヘッダー)およびメッセージ送受信モード

1.RabbitMQ交換タイプ

RabbitMQで一般的に使用される交換には、直接、トピック、ファンアウト、ヘッダーの4種類があります。AMQPプロトコルでは、システムとカスタムの2つのタイプについても言及されていますが、ここでは説明しません。これらの4つのタイプを以下に1つずつ説明します。

1.1ダイレクトタイプ

直接型交換には非常に単純なルーティングルールがあり、BindingKeyとRoutingKeyが完全に一致するキューにメッセージをルーティングします。

直接交換はRabbitMQのデフォルトの交換モードであり、最も単純なモードでもあります。RoutingKeyの完全一致に基づいてキューを検索します。

1.2トピックタイプ

前述のように、ダイレクトタイプスイッチのルーティングルールはBindingKeyとRoutingKeyを完全に一致させる必要がありますが、この厳密な一致方法では実際のビジネスニーズを満たすことができない場合が多くあります。トピックタイプの交換は、マッチングルールで拡張されました。これは、ダイレクトタイプの交換に似ています。また、BindingKeyとRoutingKeyに一致するキューにメッセージをルーティングしますが、ここでのマッチングルールは多少異なります。

(1)RoutingKeyは、com.rabbitmq.client、java.util。concurrent、com.hiddenのように、ドット「。」で区切られた文字列です(ドット「。」で区切られたそれぞれの独立した文字列は単語と呼ばれます)。クライアント;

(2)BindingKeyとRoutingKeyも、ドット「。」で区切られた文字列です。

(3)BindingKeyには、アスタリスク「*」とポンド記号「#」の2つの特殊文字列を含めることができます。これらは、ファジーマッチングに使用され、アスタリスク「*」は単語のマッチングに使用され、ポンド記号「#」は複数の通常の単語(0以上の単語)を照合するために使用されます。

1.3ファンアウトタイプ

メッセージブロードキャストのモードは、RoutingKeyの値(パイプラインキーまたはルーティングモードなし)に関係なく、メッセージをそれにバインドされたすべてのキューにブロードキャストすることです。RoutingKeyが設定されている場合でも、RoutingKeyは無視されます。

1.4ヘッダータイプ

ヘッダータイプのExchangerは、ルーティングキーの一致ルールに依存せずにメッセージをルーティングしますが、送信されるメッセージコンテンツのheaders属性に従って一致します。キューとエクスチェンジをバインドするときに、キーと値のペアのセットを作成します。メッセージをエクスチェンジに送信すると、RabbitMQはメッセージヘッダー(キーと値のペアの形式でも)を取得し、キーと値のペアを比較します。ペアが完全に一致するキューと交換がバインドされるときに指定されたキーと値のペア。完全に一致する場合、メッセージはこのキューにルーティングされます。一致しない場合、メッセージはこのキューにルーティングされません。ヘッダータイプスイッチのパフォーマンスは低下し、実用的ではありません。基本的に、その存在はわかりません。

 

2.RabbitMQメッセージの送受信モード

以下では、RabbitMQの送受信モードを例を挙げて説明します。まず、2つのSpringBootプロジェクトを作成し、RabbitMQクライアントを統合する必要があります。

(1)最初のSpringBootプロジェクト(rabbitmq-providerメッセージプッシュプロジェクト)を作成します。プロジェクトの構造は次のとおりです。

pom.xml構成情報ファイルで、関連する依存ファイルを追加します。

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

application.yml構成ファイルでRabbitMQサービスを構成します。

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

(2)2番目のSpringBootプロジェクト(rabbitmq-コンシューマーメッセージ受信プロジェクト)を作成します。プロジェクトの構造は次のとおりです。

pom.xml構成情報ファイルで、関連する依存ファイルを追加します。

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

application.yml構成ファイルでRabbitMQサービスを構成します。

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

2.1送信キューと受信キューを実装する

ダイレクトモードを使用して、メッセージの送受信キューを実装します。

(1)キューを構成します

rabbitmq-provider(メッセージプッシュプロジェクト)で、キューの名前を構成し、キューをIoC管理に転送します。コードは次のとおりです。

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)送信者を作成する

rabbitmq-provider(メッセージプッシュプロジェクト)で、送信者を作成し、rabbitTemplate.convertAndSend()メソッドを使用してメッセージを送信します。コードは次のとおりです。

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)レシーバーを作成する

rabbitmq-consumer(メッセージ受信プロジェクト)で、受信者を作成します。送信者と受信者のキュー名は同じである必要があります。同じでない場合、メッセージを受信できません。コードは次のように表示されます。

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

rabbitmq-provider(メッセージプッシュプロジェクト)でsendingメソッドを実行し、次にrabbitmq-consumer(メッセージ受信プロジェクト)を実行すると、コンソールから実行結果が表示されます。

結果:

 

2.2レシーバーで複数のトピックを受信する実装

トピックモードはRabbitMQで最も柔軟なモードであり、RoutingKeyに従ってさまざまなキューを自由にバインドできます。

(1)トピックモードを設定する

rabbitmq-provider(メッセージプッシュプロジェクト)で、メッセージを処理するためのキューを構成します。コードは次のとおりです。

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)送信者を作成する

rabbitmq-provider(メッセージプッシュプロジェクト)で、送信者を作成し、さまざまなRoutingKeysを送信して効果をテストします。コードは次のように表示されます。

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)レシーバーを作成する

rabbitmq-consumer(メッセージ受信プロジェクト)で、レシーバーAを作成します。コードは次のように表示されます。

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

rabbitmq-consumer(メッセージ受信プロジェクト)で、レシーバーBを作成します。コードは次のように表示されます。

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

それぞれrabbitmq-provider(メッセージプッシュプロジェクト)でsendingメソッドを実行し、次にrabbitmq-consumer(メッセージ受信プロジェクト)を実行すると、コンソールから実行結果が表示されます。

実行結果1:

実行結果2:

実施結果3:

 

2.3ブロードキャストモードを実現する

ファンアウトタイプのスイッチは、ブロードキャストモードを実装できます。このモードでは、エクスチェンジにバインドされているすべてのキューがこのメッセージを受信できます。

(1)ファンアウトタイプを設定する

rabbitmq-provider(メッセージプッシュプロジェクト)で、ブロードキャストモードのオブジェクトを構成します。コードは次のように表示されます。

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)送信者を作成する

rabbitmq-provider(メッセージプッシュプロジェクト)で、送信者を作成します。コードは次のとおりです。

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)レシーバーを作成する

rabbitmq-consumer(メッセージ受信プロジェクト)で、レシーバーAを作成します。コードは次のように表示されます。

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

rabbitmq-consumer(メッセージ受信プロジェクト)で、レシーバーBを作成します。コードは次のように表示されます。

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

 rabbitmq-consumer(メッセージ受信プロジェクト)で、レシーバーCを作成します。コードは次のように表示されます。

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

rabbitmq-provider(メッセージプッシュプロジェクト)でsendingメソッドを実行し、次にrabbitmq-consumer(メッセージ受信プロジェクト)を実行すると、コンソールから実行結果が表示されます。

結果:

 

おすすめ

転載: blog.csdn.net/pan_junbiao/article/details/112838589