RabbitMQ 路由(Routing)模式示例
总结自:BV15k4y1k7Ep
模式说明
和消费订阅模式相比,路由模式特点:
- 交换机的类型为 Direct。
- 队列与交换机绑定时,要指定一个
Routing key
(路由 key)。 - 消息的发送方在向 Exchange 发送消息时,也必须指定消息的
Routing key
。 - Exchange 不再把消息交给每一个绑定的队列,而是根据消息的
Routing key
进行判断,只有队列的Routing key
与消息的Routing key
完全一致,才会接收到消息。
图解:
- P:生产者,向 Exchange 发送消息,发送消息时,会指定一个 routing key。
- X:Exchange(交换机),接收生产者的消息,然后把消息递交给 与 routing key 完全匹配的队列
- C1:消费者,其所在队列指定了需要 routing key 为 error 的消息
- C2:消费者,其所在队列指定了需要 routing key 为 info、error、warning 的消息
代码
在编码上与Publish/Subscribe
模式的区别是交换机的类型为 Direct,还有队列绑定交换机的时候需要指定 routing key。
1)生产者
package com.zhangmingge.rabbitmq.routing; import com.rabbitmq.client.BuiltinExchangeType; import com.rabbitmq.client.Channel; import com.rabbitmq.client.Connection; import com.zhangmingge.rabbitmq.ConnectionUtil; /** * 路由模式的交换机类型为:direct */ public class Producer { // 交换机名称 static final String DIRECT_EXCHANGE = "direct_exchange"; // 队列名称 static final String DIRECT_QUEUE_INSERT = "direct_queue_insert"; // 队列名称 static final String DIRECT_QUEUE_UPDATE = "direct_queue_update"; public static void main(String[] args) throws Exception { // 创建连接 Connection connection = ConnectionUtil.getConnection(); // 创建频道 Channel channel = connection.createChannel(); /* * 声明交换机 * 参数 1:交换机名称 * 参数 2:交换机类型,fanout、topic、direct、headers */ channel.exchangeDeclare(DIRECT_EXCHANGE, BuiltinExchangeType.DIRECT); // 声明(创建)队列 /* * 参数 1:队列名称 * 参数 2:是否定义持久化队列 * 参数 3:是否独占本次连接 * 参数 4:是否在不使用的时候自动删除队列 * 参数 5:队列其它参数 */ channel.queueDeclare(DIRECT_QUEUE_INSERT, true, false, false, null); channel.queueDeclare(DIRECT_QUEUE_UPDATE, true, false, false, null); // 队列绑定交换机 channel.queueBind(DIRECT_QUEUE_INSERT, DIRECT_EXCHANGE, "insert"); channel.queueBind(DIRECT_QUEUE_UPDATE, DIRECT_EXCHANGE, "update"); // 发送信息 String message = "新增了商品。路由模式;routing key 为 insert "; /* * 参数 1:交换机名称,如果没有指定则使用默认 Default Exchange * 参数 2:路由 key,简单模式可以传递队列名称 * 参数 3:消息其它属性 * 参数 4:消息内容 */ channel.basicPublish(DIRECT_EXCHANGE, "insert", null, message.getBytes()); System.out.println("已发送消息:" + message); // 发送信息 message = "修改了商品。路由模式;routing key 为 update"; /* * 参数 1:交换机名称,如果没有指定则使用默认 Default Exchange * 参数 2:路由 key,简单模式可以传递队列名称 * 参数 3:消息其它属性 * 参数 4:消息内容 */ channel.basicPublish(DIRECT_EXCHANGE, "update", null, message.getBytes()); System.out.println("已发送消息:" + message); // 关闭资源 channel.close(); connection.close(); } }
注意其中声明的交换机的类型为 Direct:
channel.exchangeDeclare(DIRECT_EXCHANGE, BuiltinExchangeType.DIRECT);
队列绑定到交换机时指定了 routing key:
// 队列绑定交换机 channel.queueBind(DIRECT_QUEUE_INSERT, DIRECT_EXCHANGE, "insert"); channel.queueBind(DIRECT_QUEUE_UPDATE, DIRECT_EXCHANGE, "update");
发送消息时同样指定了 routing key:
/* * 参数 1:交换机名称,如果没有指定则使用默认 Default Exchange * 参数 2:路由 key,简单模式可以传递队列名称 * 参数 3:消息其它属性 * 参数 4:消息内容 */ channel.basicPublish(DIRECT_EXCHANGE, "update", null, message.getBytes());
2)消费者 1
package com.zhangmingge.rabbitmq.routing; import com.rabbitmq.client.*; import com.zhangmingge.rabbitmq.ConnectionUtil; import java.io.IOException; public class Consumer1 { public static void main(String[] args) throws Exception { Connection connection = ConnectionUtil.getConnection(); // 创建频道 Channel channel = connection.createChannel(); // 声明交换机 channel.exchangeDeclare(Producer.DIRECT_EXCHANGE, BuiltinExchangeType.DIRECT); // 声明(创建)队列 /* * 参数 1:队列名称 * 参数 2:是否定义持久化队列 * 参数 3:是否独占本次连接 * 参数 4:是否在不使用的时候自动删除队列 * 参数 5:队列其它参数 */ channel.queueDeclare(Producer.DIRECT_QUEUE_INSERT, true, false, false, null); // 队列绑定交换机 channel.queueBind(Producer.DIRECT_QUEUE_INSERT, Producer.DIRECT_EXCHANGE, "insert"); // 创建消费者;并设置消息处理 DefaultConsumer consumer = new DefaultConsumer(channel) { @Override /* * consumerTag 消息者标签,在 channel.basicConsume 时候可以指定 * envelope 消息包的内容,可从中获取消息 id,消息 routingkey,交换机,消息和重传标志 (收到消息失败后是否需要重新发送) * properties 属性信息 * body 消息 */ public void handleDelivery(String consumerTag, Envelope envelope, AMQP.BasicProperties properties, byte[] body) throws IOException { // 路由 key System.out.println("路由 key 为:" + envelope.getRoutingKey()); // 交换机 System.out.println("交换机为:" + envelope.getExchange()); // 消息 id System.out.println("消息 id 为:" + envelope.getDeliveryTag()); // 收到的消息 System.out.println("消费者 1-接收到的消息为:" + new String(body, "utf-8")); } }; // 监听消息 /* * 参数 1:队列名称 * 参数 2:是否自动确认,设置为 true 为表示消息接收到自动向 mq 回复接收到了,mq 接收到回复会删除消息,设置为 false 则需要手动确认 * 参数 3:消息接收到后回调 */ channel.basicConsume(Producer.DIRECT_QUEUE_INSERT, true, consumer); } }
注意其中声明的交换机的类型为 Direct:
channel.exchangeDeclare(Producer.DIRECT_EXCHANGE, BuiltinExchangeType.DIRECT);
队列绑定到交换机时指定了 routing key:
channel.queueBind(Producer.DIRECT_QUEUE_INSERT, Producer.DIRECT_EXCHANGE, "insert");
3)消费者 2
消费者 2 和消费者 1 只有日志内容和所绑定队列不同,其他没有区别。
package com.zhangmingge.rabbitmq.routing; import com.rabbitmq.client.*; import com.zhangmingge.rabbitmq.ConnectionUtil; import java.io.IOException; public class Consumer2 { public static void main(String[] args) throws Exception { ... // 声明(创建)队列 channel.queueDeclare(Producer.DIRECT_QUEUE_UPDATE, true, false, false, null); // 队列绑定交换机 channel.queueBind(Producer.DIRECT_QUEUE_UPDATE, Producer.DIRECT_EXCHANGE, "update"); // 创建消费者;并设置消息处理 DefaultConsumer consumer = new DefaultConsumer(channel) { @Override public void handleDelivery(String consumerTag, Envelope envelope, AMQP.BasicProperties properties, byte[] body) throws IOException { ... System.out.println("消费者 2-接收到的消息为:" + new String(body, "utf-8")); } }; // 监听消息 channel.basicConsume(Producer.DIRECT_QUEUE_UPDATE, true, consumer); } }
测试
启动所有消费者,然后使用生产者发送消息;在消费者对应的控制台可以查看到生产者发送对应 routing key 对应队列的消息;到达按照需要接收的效果。
在执行完测试代码后,其实到 RabbitMQ 的管理后台找到Exchanges
选项卡,点击 direct_exchange
的交换机,可以查看到如下的绑定:
![]() |
小结
Routing 模式的交换机类型为 Direct,要求队列在绑定交换机时要指定 routing key,消息会转发到符合 routing key 的队列。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 周边上新:园子的第一款马克杯温暖上架
· Open-Sora 2.0 重磅开源!
· 分享 3 个 .NET 开源的文件压缩处理库,助力快速实现文件压缩解压功能!
· Ollama——大语言模型本地部署的极速利器
· DeepSeek如何颠覆传统软件测试?测试工程师会被淘汰吗?