RabbitMQ-消息中间件(四)路由
路由
上面一节我们用交换机fanout
的方式进行了广播,这种方式如果在不需要对消息进行区分是没关系的,可以使用。但是有些场景下,比如日志打印,对于一些error的日志,我可能需要的是要保存到磁盘中进行持久化,而对于一些warn,info的日志,我可能只是想着输出下就可以了。那么这种情况下我们还用fanout的方式可能就不行了,我可能想要的是某一个队列接受特定的某一类消息做特别处理。比如我想要一个error队列专门来监听error的消息做打印,其它的队列就不管error的消息了。
绑定(Bingdings)
在前面,其实我们已经创建过“绑定”了。比如我们使用到了:channel.queueBind(queueName, EXCHANGE_NAME, "");
,“绑定”:中文意思就是你和我之间有些关联,我们之间有关系;那么MQ也是,它的关联是队列
和交换机
,它绑定的是队列和交换机的关系,也就是说,这个队列对这个交换机感兴趣,会接受这个交换机的信息。但是接受什么消息了?这个可以在绑定的时候用另外一个参数来设置,也就是路由
:俗成绑定的key。channel.queueBind(queueName, EXCHANGE_NAME, "binding key,set by yourself");
。这里我们可以看到,绑定key
是否生效其实是跟交换机
类型相关的,如果交换机是fanout
,那就跟key
没关系了,因为它是广播,只要有队列绑定到我交换机,产生了关系,我就懒的管你要不要,直接给你。这个有点类似中国爸妈,你是我孩子,只要我想给,你不要也得要,哈哈。
Direct 交换机
前面章节,我们采用的fanout
交换机,它是给所有队列发送消息。很明显在我们的日志系统需求里面不太适合,我们希望对消息进行一次过滤,过滤之后再发送给不同的队列做处理,比如有的队列接受消息去打印,有的去写磁盘等等。所以请注意了如果你不想管事,那就用fanout,把消息给你,你自己去做处理,直观无脑给消息就行,其他的就不用关心了。。用不了fanout
,那我们用什么了?rabbitMQ有四种交换机,我们可以选择direct
。direct
交换机背后的算法规则很简单,队列的bingding key
和消息的routing key
那个能精确匹配就给队列发消息。
图中非常简单,两个队列同时绑定了direct
交换机,Q1的范围是根据bingding key
为orange的值得消息。它表明,如果消息中的routing key
为orange,那么消息就发送给Q1。Q2绑定了两个:black、green,如果消息中有routing key
为black和green的都发送个Q2。那么如果消息没有routing key,或者队列没有bingding key,那么这种消息,交换机会直接丢弃。
多绑定
多个队列绑定同一个bingding key
,在rabbitMQ中是合法的。如上图中,如果是这种形式,那么direct
交换机的作用就是类似fanout
,不过只有当消息的routing key
和bingding key
一直,上图中是消息如果路由key是black,那么交换机就会将消息分发给Q1和Q2两个队列。
实践: 发送日志(生产者)
现在回到我们之前的问题,如果我们想要不同的队列,比如Q1将日志写入磁盘,Q2打印warn日志,Q3接收info日志。我们可以使用drect
交换机,然后给不同的队列绑定bingding key
。所以对于我们的生产者端:
- 声明交换机还是跟之前的类似,我们必须先声明一个交换机:
1 | channel.exchangeDeclare(EXCHANGE_NAME,"direct"); |
- 传递消息:
1 | channel.basicPublish(EXCHANGE_NAME, severity, null, message.getBytes()); |
订阅(Subscribing)
消费者对消息的接收和之前的有一个不同,我们用bingding key来绑定消费者只对感兴趣的消息进行接收:
1 | String queueName = channel.queueDeclare().getQueue(); |
代码
生产者,在发送消息的时候特别注意routing key
,在此例子中也就是我们for循环里面的key:
1 | package me.chenzhijun.route; |
消费者,这里我们使用的是两种方式,第一种是全部绑定到一个队列,另外注释的是开启4个队列,对不动的消息做不同的处理:
1 | package me.chenzhijun.route; |
参考文档: