3.4.1 介绍
在Fanout模式中,一条消息,会被所有订阅的队列都消费。但是,在某些场景下,我们希望不同的消息被不同的队列消费。这时就要用到Direct类型的Exchange。
在Direct模型下:
● 队列与交换机的绑定,不能是任意绑定了,而是要指定一个RoutingKey(路由key)
● 消息的发送方在 向 Exchange发送消息时,也必须指定消息的 RoutingKey。
● Exchange不再把消息交给每一个绑定的队列,而是根据消息的Routing Key进行判断,只有队列的Routingkey与消息的 Routing key完全一致,才会接收到消息
案例需求如图:
- 声明一个名为hmall.direct的交换机
- 声明队列direct.queue1,绑定hmall.direct,bindingKey为blud和red
- 声明队列direct.queue2,绑定hmall.direct,bindingKey为yellow和red
- 在consumer服务中,编写两个消费者方法,分别监听direct.queue1和direct.queue2
- 在publisher中编写测试方法,向hmall.direct发送消息
3.4.2 测试
3.4.2.1 创建队列和交换机
首先在控制台声明两个队列direct.queue1和direct.queue2,这里不再展示过程:
然后声明一个direct类型的交换机,命名为hmall.direct:
然后使用red和blue作为key,绑定direct.queue1到hmall.direct:
同理,使用red和yellow作为key,绑定direct.queue2到hmall.direct,步骤略,最终结果:
3.4.2.2 监听队列
在consumer服务的SpringRabbitListener中添加方法:
@RabbitListener(queues = "direct.queue1")
public void listenDirectQueue1(String msg) {
System.out.println("消费者1接收到direct.queue1的消息:【" + msg + "】");
}
@RabbitListener(queues = "direct.queue2")
public void listenDirectQueue2(String msg) {
System.out.println("消费者2接收到direct.queue2的消息:【" + msg + "】");
}
3.4.2.3 消息发送
在publisher服务的SpringAmqpTest类中添加测试方法:
@Test
public void testSendDirectExchange() {
// 交换机名称
String exchangeName = "hmall.direct";
// 消息
String message = "红色警报!日本乱排核废水,导致海洋生物变异,惊现哥斯拉!";
// 发送消息
rabbitTemplate.convertAndSend(exchangeName, "red", message);
}
由于使用的red这个key,所以两个消费者都收到了消息:
我们再切换为blue这个key:
@Test
public void testSendDirectExchange() {
// 交换机名称
String exchangeName = "hmall.direct";
// 消息
String message = "最新报道,哥斯拉是居民自治巨型气球,虚惊一场!";
// 发送消息
rabbitTemplate.convertAndSend(exchangeName, "blue", message);
}
你会发现,只有消费者1收到了消息:
3.4.3 小结
描述下Direct交换机与Fanout交换机的差异?
● Fanout交换机将消息路由给每一个与之绑定的队列
● Direct交换机根据RoutingKey判断路由给哪个队列
● 如果多个队列具有相同的RoutingKey,则与Fanout功能类似
3.5.Topic交换机(自行测试)
3.5.1 介绍
Topic类型的Exchange与Direct相比,都是可以根据RoutingKey把消息路由到不同的队列。
只不过Topic类型Exchange可以让队列在绑定BindingKey 的时候使用通配符!
BindingKey 一般都是有一个或多个单词组成,多个单词之间以.分割,例如: item.insert
通配符规则:
● #:匹配零个或多个词
● :匹配不多不少恰好1个词
举例:
● item.#:能够匹配item.spu.insert 或者 item.spu
● item.:只能匹配item.spu
图示:
假如此时publisher发送的消息使用的RoutingKey共有四种:
● china.news 代表有中国的新闻消息;
● china.weather 代表中国的天气消息;
● japan.news 则代表日本新闻
● japan.weather 代表日本的天气消息;
解释:
● topic.queue1:绑定的是china.# ,凡是以 china.开头的routing key 都会被匹配到,包括:
○ china.news
○ china.weather
● topic.queue2:绑定的是#.news ,凡是以 .news结尾的 routing key 都会被匹配。包括:
○ china.news
○ japan.news
3.5.2 测试
3.5.2.1 创建队列和交换机
接下来,我们就按照上图所示,来演示一下Topic交换机的用法。
首先,在控制台按照图示例子创建队列、交换机,并利用通配符绑定队列和交换机。
创建队列:topic.queue1、topic.queue2
创建交换机:hmall.topic
绑定队列:
topic.queue1:绑定的是china.#
topic.queue2:绑定的是#.news
最终结果如下:
3.5.2.2 消息接收
在consumer服务的SpringRabbitListener中添加方法:
@RabbitListener(queues = "topic.queue1")
public void listenTopicQueue1(String msg){
System.out.println("消费者1接收到topic.queue1的消息:【" + msg + "】");
}
@RabbitListener(queues = "topic.queue2")
public void listenTopicQueue2(String msg){
System.out.println("消费者2接收到topic.queue2的消息:【" + msg + "】");
}
3.5.2.3 消息发送
在publisher服务的SpringAmqpTest类中添加测试方法:
/**
- topicExchange
/
@Test
public void testSendTopicExchange() {
// 交换机名称
String exchangeName = "hmall.topic";
// 消息
String message = "喜报!孙悟空大战哥斯拉,胜!";
// 发送消息
rabbitTemplate.convertAndSend(exchangeName, "china.news", message);
}
执行测试方法,routingKey为china.news可以匹配topic.queue1和topic.queue2,日志输出:
消费者1接收到topic.queue1的消息:【喜报!孙悟空大战哥斯拉,胜!】
消费者2接收到topic.queue2的消息:【喜报!孙悟空大战哥斯拉,胜!】
更改routingKey为china.weather,只可以匹配到topic.queue1,日志输出:
消费者1接收到topic.queue1的消息:【喜报!孙悟空大战哥斯拉,胜!】
3.5.3 小结
描述下Direct交换机与Topic交换机的差异?
● Topic交换机接收的消息RoutingKey必须是多个单词,以 . 分割
● Topic交换机与队列绑定时的bindingKey可以指定通配符
● #:代表0个或多个词
● :代表1个词