《RabbitMQ系列》之RabbitMQ的4种Exchange
大家好,我是 tc,今天为大家介绍一下RabbitMQ中的4种exchange,水平一般,能力有限,若有错误之处,欢迎指正。
![](https://pica.zhimg.com/80/v2-03b8a4c57f85cf4f324b438983e66994_1440w.jpg)
对RabbitMQ稍有了解的朋友应该都知道,在RabbitMQ中,一个有4中Exchange,分别是direct、topic、fanout、headers。
其实,还有一个默认的交换机,称为default exchange,其本质也是一个direct exchange。在这4种exchange中,最常用的是direct、topic、fanout。
下面,我们就通过代码示例分别介绍这4种exchange的用法,以及应用场景。
本文中代码涉及到的RabbitMQ的配置如下。
![](https://picx.zhimg.com/80/v2-69eeb9c8526b6f97aed4bee931a37025_1440w.jpg)
本文中代码涉及到的MAVEN依赖如下。
![](https://pic1.zhimg.com/80/v2-df73633dd8450920f362abfa1796434a_1440w.webp)
direct exchange
此种类型的交换机是通过routing key 和队列绑定在一起的。
通过一个routing key,交换机可以绑定一个队列,也可以同时绑定多个队列。
如果一个交换机绑定了多个队列,则交换机会将消息分别路由给每一个队列,也就是说每个队列都会得到一份全量的消息。
例如,交换机绑定了2个队列,接到生产者的10条消息后,不是分别向两个队列发送5条消息,而是向2个队列都发送10条消息。
下面,我们通过代码简单演示一下direct exchange的使用方式。
交换机绑定一个队列
![](https://pic3.zhimg.com/80/v2-6f7f2d4acd14ab7d727e7fef1cefee16_1440w.webp)
启动类RabbitmqDemoApplication代码如下
![](https://pic1.zhimg.com/80/v2-f7472f7ab50afc7ee987225c0bebb5c0_1440w.webp)
@EnableRabbit注解的作用是开启基于注解的RabbitMQ。
生产者Producer代码如下
![](https://pic4.zhimg.com/80/v2-8eeeb4b5ed7c625bc38ffceeb7bd1cfd_1440w.webp)
convertAndSend方法的作用就是向RabbitMQ发送消息,第一个参数"directExchange"指交换机的名称,
第二个参数"rk.001"指routing key,第三个参数是消息。
消费者代码如下
![](https://picx.zhimg.com/80/v2-a0098b0aada32460ceb7c90e7bcd62a1_1440w.webp)
@RabbitListener注解的作用是指定目标方法来作为消费消息的方法,通过参数queues指定监听的队列,通过参数bindings指定监听的绑定。
其中,@Queue("queue.test.001") 在项目启动时,会创建一个名为queue.test.001的队列。
@Exchange("directExchange") 在项目启动时,会创建一个名为directExchange的交换机,如果不指定类型,默认就是direct exchange。
key指定交换机和队列的绑定的routing key。
通过如此配置,交换机directExchange就通过routing key“rk.001”和队列queue.test.001绑定在一起了。
一旦生产者向交换机directExchange发送消息,并指定routing key为“rk.001”,消费者consumer就可以消费消息了。
单元测试代码如下
![](https://pic4.zhimg.com/80/v2-0f31717aa2b24ac296e5a00a255f994b_1440w.webp)
测试结果如下
![](https://pic1.zhimg.com/80/v2-9005ab9e1f3ea46d913911c1f12bef68_1440w.webp)
从测试结果来看,消费者正常消费了10条消息,与我们上面的预测是一致的。
RabbitMQ控制台如下
队列信息如下图。
![](https://picx.zhimg.com/80/v2-da955fe44879eda98eea1c10b7f2c051_1440w.webp)
交换机信息如下图。
![](https://picx.zhimg.com/80/v2-012426b8a069547052c60a0f891b3af5_1440w.webp)
交换机绑定多个队列
![](https://pica.zhimg.com/80/v2-c0ecd45115ee895a7b5e72479ddb31be_1440w.webp)
除了消费者代码之外,其他代码和上面相同,就不在赘述。
消费者代码如下
![](https://pic3.zhimg.com/80/v2-9c7dcfcb62cb27bc933fe1cd6cef5f78_1440w.webp)
如上图代码所示。
我们创建了两个队列queue.test.001和queue.test.002,并都将其通过相同的routing key “rk.001”绑定到同一个交换机directExchange上。
按照我们上面的推测,这两个消费者process1和process2,都会消费10条消息。
测试结果如下
![](https://pic2.zhimg.com/80/v2-f956c2f59cc1b46b26e5da0bfd36ff43_1440w.webp)
如上图所示,测试结果证明了我们的推测是正确的。
RabbitMQ控制台如下
队列信息如下。
![](https://pic1.zhimg.com/80/v2-14893a84e58750b788da94cf67a00dc2_1440w.webp)
交换机信息如下。
![](https://pica.zhimg.com/80/v2-7071015a3d6c7bedea1a58e3af3e5b70_1440w.webp)
适用场景
1、适用于业务数据需要直接传输并消费的场景,比如不同业务模块之间的消息交互,就可以借助基于DirectExchange的消息模型进行通信。
2、点对点聊天
topic exchange
和direct exchange类似,topic exchange也是根据routing key,将exchange和queue绑定在一起。
区别在于,direct exchange的routing key 是精确匹配,而topic exchange的的routing key 是模式匹配,类似于正则表达式匹配。
routing key 可以是类似 *.orange.* 或者 lazy.# 的表达式。其中,* (星) 代表一个单词,# (hash) 代表0个或多个单词。
![](https://pic2.zhimg.com/80/v2-ad453d6b889433b222194c5beaf2491f_1440w.webp)
从上面的运行示意图中,我们可以看出queues中绑定的routing key是模糊的,usa.#这个routing key可以接收到usa.news和usa.weather的消息;而#.news这个routing key可以接收到usa.news和europe.news的消息。
下面,我们通过一个代码示例简单介绍一下topic exchange的用法,以及应用场景。
示例代码
生产者代码
![](https://picx.zhimg.com/80/v2-725708f0055bf8caefd7766ad7acb6f3_1440w.webp)
如上图所示,我们创建了四个生产者,向topicExchange交换分别发送一条消息,同时指定routing key。
消费者代码
![](https://pic4.zhimg.com/80/v2-122eff0e108e6ebd0e74e1103fc32acf_1440w.webp)
如上图所示,我们创建了四个消费者,并创建一个topic exchange,创建4个队列,并分别指定routing key,其中,*表示一个单词。
单元测试代码
![](https://pic1.zhimg.com/80/v2-cc4717c300a1f2ac8050604ad11dde08_1440w.webp)
测试结果
![](https://pica.zhimg.com/80/v2-0f22d36a795369356d86f052fc375ef2_1440w.webp)
从上图可以看出:
消费者一通过routing key(usa.*)消费了两条和usa相关的消息,分别是生产者一和生产者二发送的消息;
消费者二通过routing key(*.news)消费了两条和news相关的消息,分别是生产者一和生产者三发送的消息;
消费者三通过routing key(europe.*)消费了两条和europe相关的消息,分别是生产者三和生产者四发送的消息;
消费者四通过routing key(*.weather)消费了两条和weather相关的消息,分别是生产者二和生产者四发送的消息;
和我们上面的推测是一致的。
RabbitMQ控制台信息
队列信息如下,可以看出我们创建了4个队列。
![](https://pic1.zhimg.com/80/v2-8966b5e63e94faf889c8f04d17bbd408_1440w.webp)
交换机信息如下,可以看出我们创建了一个topic类型的交换机。
![](https://pic1.zhimg.com/80/v2-499c34682c68dbc677f3f5844e82619c_1440w.webp)
适用场景
1、涉及分类或标记的新闻更新,例如体育新闻、娱乐新闻、社会新闻、金融新闻等分类推送。
2、后台任务处理,每个工作线程处理特定的任务。
fanout exchange
和direct exchange、topic exchange不同,fanout exchange不使用routing key,它会将消息路由到所有与其绑定的队列。
fanout exchange是消息广播路由的理想选择。
和direct exchange的一个交换机绑定多个队列的情况一样,绑定了fanout exchange的队列,都会接收到一份全量的消息。
![](https://pic4.zhimg.com/80/v2-d6805cab68f02c0a9ee9158ce584c4c1_1440w.webp)
示例代码
生产者代码
![](https://pic3.zhimg.com/80/v2-babe830c2ad5ebe10938a60cfbadacde_1440w.webp)
我们创建了4个生产者,指定交换机为fanoutExchange,但是没有指定routing key。
消费者代码
![](https://pic4.zhimg.com/80/v2-472f2a2abb1255cdba18cf31068882c3_1440w.webp)
如上图,我们创建了4个消费者,同样指定交换机是fanoutExchange,且类型是fanout,同时还指定了routing key。
单元测试代码
![](https://pic1.zhimg.com/80/v2-17c255db61cb13d2aa668a3adf4597c6_1440w.webp)
测试结果
![](https://pic2.zhimg.com/80/v2-79b99bdc03e96f4cb3eb0d2ba09464f5_1440w.webp)
从上图的测试结果中可以看出,绑定了fanout exchange的每一个队列,都全量消费了消息。
我们在发送消息时,只指定了交换机,没有指定routing key,在消费者这边也指定了交换机,同时还指定了routing key,结果每个绑定了交换机的队列都可以消费到全量消息,这说明了fanout exchange不使用routing key,它会将消息路由到所有与其绑定的队列。
RabbitMQ控制台信息
队列信息如下。
![](https://pic2.zhimg.com/80/v2-03869f8083571ba30aa71f08948fac7b_1440w.webp)
交换机信息如下。
![](https://pic1.zhimg.com/80/v2-8038e5a905085321ea001e204c393054_1440w.webp)
适用场景
1、适用于广播消息的场景
2、群聊功能,广播消息给当前群聊中的所有人
3、大型多人在线游戏的游戏积分排行榜更新
4、体育新闻客户端实时更新分数
5、分布式系统可以广播各种状态和配置更新
headers exchange
和上面三种交换机类型不同,headers exchange是根据Message的一些头部信息来分发过滤Message的,它会忽略routing key的属性,如果Header信息和message消息的头信息相匹配,那么这条消息就匹配上了。
有一个重要参数x-match:当“x-match”参数设置为“any”时,只要一个匹配的header 属性值就足够了;当“x-match”设置为“all”时,意味着所有值都必须匹配,才能将交换机和队列绑定上。
![](https://pic3.zhimg.com/80/v2-1d771c854bd3aa27461c788e6d2e7afa_1440w.webp)
示例代码
配置代码
![](https://pic1.zhimg.com/80/v2-dcda5257c57100a817505cb7596c186c_1440w.webp)
如上图所示,我们配置了三个队列:queue.headers.001、queue.headers.002和queue.headers.003,并创建了一个Headers类型的交换机headerExchange。
将队列queue.headers.001绑定到headerExchange上,并指定x-match=any,绑定的属性分别是type = 1,name = send11,也就是说,只能有一个属性可以匹配上,消费者就可以消费消息。
将队列queue.headers.002绑定到headerExchange上,并指定x-match=all,绑定的属性分别是type = 2,name = send2,也就是说,必须两个属性都匹配上,消费者才可以消费消息。
将队列queue.headers.003绑定到headerExchange上,并指定x-match=all,绑定的属性分别是type = 3,name = send33,也就是说,必须两个属性都匹配上,消费者才可以消费消息。
生产者代码
![](https://pic1.zhimg.com/80/v2-2b5186bc08fb33f9839d951c53ca54fe_1440w.webp)
如上图所示,我们配置了三个生产者。
生产者一向交换机headerExchange发送消息,同时指定了两个headers属性:type = 1,name = send1;
生产者二向交换机headerExchange发送消息,同时指定了两个headers属性:type = 2,name = send2;
生产者三向交换机headerExchange发送消息,同时指定了两个headers属性:type = 3,name = send3;
消费者代码
![](https://pic4.zhimg.com/80/v2-b4548229d0d5d91f226461da97da4f91_1440w.webp)
如上图所示,我们配置了三个消费者,分别消费队列queue.headers.001、queue.headers.002和queue.headers.003的消息。
我们在上面的配置文件中,将queue.headers.001和headerExchange绑定在一起了,且只要有一个headers属性匹配上就可以消费消息;
将queue.headers.002、queue.headers.003也和headerExchange绑定在一起了,且必须所有的headers属性都匹配上才可以消费消息;
从上面的代码中,我们可以作出如下推测:
1、消费者一可以正常消费消息。因为生产者一发送消息时指定了type = 1,name = send1属性,而在配置文件中,同样配置了type = 1,name = send11属性,且x-match = any,正好有一个type = 1 属性是可以匹配上的,故而可以可以正常消费消息。
2、消费者二可以正常消费消息。因为生产者二发送消息时指定了type = 2,name = send2属性,而在配置文件中,同样配置了type = 2,name = send2属性,且x-match = all,两个headers属性都可以匹配上,故而可以正常消费消息。
3、消费者三不可以正常消费消息。因为生产者三发送消息时指定了type = 3,name = send3属性,而在配置文件中,同样配置了type = 3,name = send33属性,且x-match = all,两个headers属性只有type可以匹配上,故而不可以正常消费消息。
单元测试代码
![](https://pica.zhimg.com/80/v2-c612005b5b34b3fa1a40d72216db6ac4_1440w.webp)
测试结果
![](https://pic1.zhimg.com/80/v2-6871baec84946b01cdd09e3b9370d140_1440w.webp)
从上图可以看出,消费者一和消费者二可以正常消费消息,但是消费者三没有消费,因为没有匹配上。
RabbitMQ控制台信息
队列信息如下。
![](https://pic2.zhimg.com/80/v2-4dd9bbd1da336daeaffb0fd2bcd9a2f1_1440w.webp)
交换机信息如下。
![](https://pic2.zhimg.com/80/v2-fab3af2d5a0e5bb1cab179f63f477ec9_1440w.webp)
适用场景
1、适用于routing key非常复杂或者灵活多变的场景