网站首页 > 技术文章 正文
在上一章中,我们构建了一个简单的日志系统,我们可以把消息广播给很多的消费者。在本章中我们将增加一个特性:我们可以订阅这些信息中的一些信息。例如,我们希望只将error级别的错误存储到硬盘中,同时可以将所有级别(error、info、warning等)的日志都打印在控制台上。
1、绑定(Bindings)
在上一章中,我们已经创建了绑定关系,回顾一下代码:
1 channel.queueBind(queueName, EXCHANGE_NAME, "");
一个绑定是一个交换器与队列之间的关系。意思是指:这个队列对这个交换器的消息感兴趣。
该方法同时还有另一个routing Key参数,为了避免与basic_public参数产生中的路由键(routing key)混淆,我们称之为绑定键(bingind key),下面展示了如何通过一个绑定key创建一个绑定:
1 channel.queueBind(queueName, EXCHANGE_NAME, "black");
注意,这个绑定键(这里是"black")的含义依赖于交换器的类型。比如在我们的日志系统中,交换器类型为fanout,此时,绑定键没有任何意义,会被忽略掉。
2、直连交换机(Direct Exchange)
在我们之前的日志系统中,所有的消息被广播给所有的消费者,但是本章的需要是希望有一个程序可以只接收error级别的日志并保存到磁盘中,而不用浪费空间去存储那些info、warning级别的日志。
我们正在用的广播模式的交换器并不够灵活,它只是不加思索地进行广播。因此,需要使用direct exchange来代替。直连交换器的路由算法非常简单:将消息推送到binding key与该消息的routing key相同的队列。
为了说明这点,请看下图:
在该图中,直连交换器X上绑定了两个队列。第一个队列绑定了绑定键orange,第二个队列有两个绑定键:black和green。在这种场景下,一个消息在布时指定了路由键为orange将会只被路由到队列Q1,路由键为black和green的消息都将被路由到队列Q2。其他的消息都将被丢失。
3、多重绑定
同一个绑定键可以绑定到不同的队列上去,在上图中,我们也可以增加一个交换器X与队列Q2的绑定键,在这种情况下,直连交换器将会和广播交换器有着相同的行为,将消息推送到所有匹配的队列。一个路由键为black的消息将会同时被推送到队列Q1和Q2。
4、发送日志
首先我们要一如既往地创建一个交换器:
1 channel.exchangeDeclare(EXCHANGE_NAME, "direct");
并准备发送消息:
1 channel.basicPublish(EXCHANGE_NAME, severity, null, message.getBytes());
我们需要确保在我们日志系统中参数"severity"是“info”、“warning”和“error”中的一个。
5、订阅
创建接收消息与上一章基本相同,唯一不同的是,需要在创建绑定关系时,指定severity的值:
1 String queueName = channel.queueDeclare().getQueue(); 2 3 for(String severity : argv){ 4 channel.queueBind(queueName, EXCHANGE_NAME, severity); 5 }
6、完整的代码
EmitLogDirect.java
import com.rabbitmq.client.Channel; import com.rabbitmq.client.Connection; import com.rabbitmq.client.ConnectionFactory; public class EmitLogDirect { private static final String EXCHANGE_NAME = "direct_logs"; public static void main(String[] argv) throws Exception { ConnectionFactory factory = new ConnectionFactory(); factory.setHost("localhost"); try (Connection connection = factory.newConnection(); Channel channel = connection.createChannel()) { channel.exchangeDeclare(EXCHANGE_NAME, "direct"); String severity = getSeverity(argv); String message = getMessage(argv); channel.basicPublish(EXCHANGE_NAME, severity, null, message.getBytes("UTF-8")); System.out.println(" [x] Sent '" + severity + "':'" + message + "'"); } } //.. }
ReceiveLogsDirect.java
import com.rabbitmq.client.*; public class ReceiveLogsDirect { private static final String EXCHANGE_NAME = "direct_logs"; public static void main(String[] argv) throws Exception { ConnectionFactory factory = new ConnectionFactory(); factory.setHost("localhost"); Connection connection = factory.newConnection(); Channel channel = connection.createChannel(); channel.exchangeDeclare(EXCHANGE_NAME, "direct"); String queueName = channel.queueDeclare().getQueue(); if (argv.length < 1) { System.err.println("Usage: ReceiveLogsDirect [info] [warning] [error]"); System.exit(1); } for (String severity : argv) { channel.queueBind(queueName, EXCHANGE_NAME, severity); } System.out.println(" [*] Waiting for messages. To exit press CTRL+C"); DeliverCallback deliverCallback = (consumerTag, delivery) -> { String message = new String(delivery.getBody(), "UTF-8"); System.out.println(" [x] Received '" + delivery.getEnvelope().getRoutingKey() + "':'" + message + "'"); }; channel.basicConsume(queueName, true, deliverCallback, consumerTag -> { }); } }
为了测试方便,我们可以把"info"、"error"、"warning"都绑定到一个队列上去,然后生产者分别往"info"、"error"、"warning"发送消息:
此时查看RabbitMq控制台:
关注我,后续更多干货奉上!
猜你喜欢
- 2024-10-02 「MQ实战」RabbitMQ 延迟队列,消息延迟推送
- 2024-10-02 未读消息(小红点),RabbitMQ实时消息推送实践,贼简单
- 2024-10-02 RabbitMQ——延迟队列,消息延迟推送
- 2024-10-02 RabbitMQ实现即时通讯居然如此简单
- 2024-10-02 RabbitMQ没有延时队列?我就教你一招,玩转延时队列
- 2024-10-02 RabbitMQ详解,用心看完这一篇就够了
- 2024-10-02 RabbitMQ原理与相关操作(三)消息持久化
- 2024-10-02 Java互联网架构-互联网大厂面试必备RabbitMQ
- 2024-10-02 RabbitMQ的介绍及使用进阶(Docker+.Net Core)
- 2024-10-02 快速尝鲜:RabbitMQ 搭建完就得用起来
你 发表评论:
欢迎- 最近发表
- 标签列表
-
- oraclesql优化 (66)
- 类的加载机制 (75)
- feignclient (62)
- 一致性hash算法 (71)
- dockfile (66)
- 锁机制 (57)
- javaresponse (60)
- 查看hive版本 (59)
- phpworkerman (57)
- spark算子 (58)
- vue双向绑定的原理 (68)
- springbootget请求 (58)
- docker网络三种模式 (67)
- spring控制反转 (71)
- data:image/jpeg (69)
- base64 (69)
- java分页 (64)
- kibanadocker (60)
- qabstracttablemodel (62)
- java生成pdf文件 (69)
- deletelater (62)
- com.aspose.words (58)
- android.mk (62)
- qopengl (73)
- epoch_millis (61)
本文暂时没有评论,来添加一个吧(●'◡'●)