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(メッセージ受信プロジェクト)を実行すると、コンソールから実行結果が表示されます。
結果: