【RabbitMQ】路由模式和通配符模式的具体实现

article/2025/8/11 23:23:37

文章目录

  • 路由模式
    • 创建队列和交换机
    • 生产者代码
      • 创建交换机
      • 声明队列
      • 绑定交换机和队列
      • 发送消息
      • 完整代码
    • 消费者代码
    • 运行程序
      • 启动生产者
      • 启动消费者
  • 通配符模式
    • 创建队列和交换机
    • 生产者代码
      • 创建交换机
      • 声明队列
      • 绑定交换机和队列
      • 发送消息
      • 完整代码
    • 消费者代码
    • 运行程序
      • 启动生产者
      • 启动消费者

路由模式

队列和交换机的绑定,不能是任意的绑定了,而是要指定一个 BindingKey (RoutingKey 的一种) 消息的发送方在向 Exchange 发送消息时,也需要指定消息的 RoutingKey

Exchange 也不再把消息交给每一个绑定的 key,而是根据消息的 RoutingKey 进行判断,只有队列绑定时的 BindingKey 和发送消息的 RoutingKey 完全一致,才会接收到消息

image.png

  • 课程中所谓的 BindingKey,是 RoutingKey 的一种
  • 早期也叫做 routingKey,只是在最新的文档中被改成 BindingKey

我们通常:

  • 把消息发送称为:Routingkey
  • 把队列绑定称为:BindingKey

创建队列和交换机

Constants 中添加:

// 路由模式  
public static final String DIRECT_EXCHANGE = "direct.exchange";  
public static final String DIRECT_QUEUE1 = "direct.queue1";  
public static final String DIRECT_QUEUE2 = "direct.queue2";

生产者代码

和发布订阅模式的区别是:交换机类型不同,绑定队列的 BindingKey 不同

创建交换机

创建交换机,定义交换机类型为 BuiltinExchangeType.DIRECT

channel.exchangeDeclare(Constants.DIRECT_EXCHANGE, BuiltinExchangeType.DIRECT, true);
  • BuiltinExchangeType 一共有四种
    1. DIRECT("direct")
    2. FANOUT("fanout")
    3. TOPIC("topic")
    4. HEADERS("headers")

声明队列

channel.queueDeclare(Constants.DIRECT_QUEUE1, true, false, false, null);  
channel.queueDeclare(Constants.DIRECT_QUEUE2, true, false, false, null);

绑定交换机和队列

// 队列1绑定 a
channel.queueBind(Constants.DIRECT_QUEUE1, Constants.DIRECT_EXCHANGE, "a");  
// 队列2 绑定 a, b, c
channel.queueBind(Constants.DIRECT_QUEUE2, Constants.DIRECT_EXCHANGE, "a");  
channel.queueBind(Constants.DIRECT_QUEUE2, Constants.DIRECT_EXCHANGE, "b");  
channel.queueBind(Constants.DIRECT_QUEUE2, Constants.DIRECT_EXCHANGE, "c");

发送消息

String msg_a = "hello direct, my routingKey is a...";  
channel.basicPublish(Constants.DIRECT_EXCHANGE, "a", null, msg_a.getBytes());  String msg_b = "hello direct, my routingKey is b...";  
channel.basicPublish(Constants.DIRECT_EXCHANGE, "b", null, msg_b.getBytes());  String msg_c = "hello direct, my routingKey is c...";  
channel.basicPublish(Constants.DIRECT_EXCHANGE, "c", null, msg_c.getBytes());
  • 发送消息时,指定 RoutingKey

完整代码

package rabbitmq.routing;  import com.rabbitmq.client.BuiltinExchangeType;  
import com.rabbitmq.client.Channel;  
import com.rabbitmq.client.Connection;  
import com.rabbitmq.client.ConnectionFactory;  
import rabbitmq.constant.Constants;  import java.io.IOException;  
import java.util.concurrent.TimeoutException;  
import java.util.function.BinaryOperator;  public class Producer {  public static void main(String[] args) throws IOException, TimeoutException {  // 1. 建立连接  ConnectionFactory connectionFactory = new ConnectionFactory();  connectionFactory.setHost(Constants.HOST);  connectionFactory.setPort(Constants.PORT);  connectionFactory.setUsername(Constants.USER_NAME);  connectionFactory.setPassword(Constants.PASSWORD);  connectionFactory.setVirtualHost(Constants.VIRTUAL_HOST);  Connection connection = connectionFactory.newConnection();  // 2. 开启信道  Channel channel = connection.createChannel();  // 3. 声明交换机  channel.exchangeDeclare(Constants.DIRECT_EXCHANGE, BuiltinExchangeType.DIRECT, true);  // 4. 声明队列  channel.queueDeclare(Constants.DIRECT_QUEUE1, true, false, false, null);  channel.queueDeclare(Constants.DIRECT_QUEUE2, true, false, false, null);  // 5. 绑定交换机和队列  channel.queueBind(Constants.DIRECT_QUEUE1, Constants.DIRECT_EXCHANGE, "a");  channel.queueBind(Constants.DIRECT_QUEUE2, Constants.DIRECT_EXCHANGE, "a");  channel.queueBind(Constants.DIRECT_QUEUE2, Constants.DIRECT_EXCHANGE, "b");  channel.queueBind(Constants.DIRECT_QUEUE2, Constants.DIRECT_EXCHANGE, "c");  // 6. 发送消息  String msg_a = "hello direct, my routingKey is a...";  channel.basicPublish(Constants.DIRECT_EXCHANGE, "a", null, msg_a.getBytes());  String msg_b = "hello direct, my routingKey is b...";  channel.basicPublish(Constants.DIRECT_EXCHANGE, "b", null, msg_b.getBytes());  String msg_c = "hello direct, my routingKey is c...";  channel.basicPublish(Constants.DIRECT_EXCHANGE, "c", null, msg_c.getBytes());  System.out.println("消息发送成功!");  // 7. 释放资源  channel.close();  connection.close();  }  
}

消费者代码

Routing 模式的消费者代码和 Publish/Subscribe 代码一样,同样复制出来两份

  • Consumer1
  • Consumer2
package rabbitmq.routing;  import com.rabbitmq.client.*;  
import rabbitmq.constant.Constants;  import java.io.IOException;  
import java.util.concurrent.TimeoutException;  public class Consumer1 {  public static void main(String[] args) throws IOException, TimeoutException {  //1. 建立连接  ConnectionFactory connectionFactory = new ConnectionFactory();  connectionFactory.setHost(Constants.HOST);  connectionFactory.setPort(Constants.PORT);  connectionFactory.setUsername(Constants.USER_NAME);  connectionFactory.setPassword(Constants.PASSWORD);  connectionFactory.setVirtualHost(Constants.VIRTUAL_HOST);  Connection connection = connectionFactory.newConnection();  //2. 建立信道  Channel channel = connection.createChannel();  //3. 声明队列  channel.queueDeclare(Constants.DIRECT_QUEUE1, true, false, false, null);  //4. 消费信息  DefaultConsumer consumer = new DefaultConsumer(channel){  @Override  public void handleDelivery(String consumerTag, Envelope envelope, AMQP.BasicProperties properties, byte[] body) throws IOException {  System.out.println("接收到消息:" + new String(body));  }  };  channel.basicConsume(Constants.DIRECT_QUEUE1, true, consumer);  }  
}

运行程序

启动生产者

  1. 消息路由 image.png|472
  • 可以看到 direct.queue1 队列中,路由了一条消息
  • 可以看到 direct.queue2 队列中,路由了两条消息
  1. 队列和交换机的绑定
    image.png|360

启动消费者

Consumer1

接收到消息:hello direct, my routingKey is a...

Consumer2

接收到消息:hello direct, my routingKey is a...
接收到消息:hello direct, my routingKey is b...
接收到消息:hello direct, my routingKey is c...

通配符模式

TopicsRouting 模式的区别是:

  1. Topics 模式使用的交换机类型是 topicRouting 模式用的交换机类型为 direct
  2. topic 类型的交换机在匹配规则上进行了扩展,Binding Key 支持通配符匹配(direct 类型的交换机路由规则是 BindingKeyRoutingKey 完全匹配)

image.png|344

Topic 类型的交换机在匹配规则上,有一些要求:

  1. RoutingKey 是由一系列由点(.) 分隔的单词,比如“stock.sd.nyse”, “nyse.vmw”, “quick.orange.rabbit
  2. BindingKeyRoutingKey 一样,也是点(.) 分割的字符串
  3. BindingKey 中可以存在两种特殊的字符串,用于模糊匹配
    • * 表示一个单词
    • # 表示多个单词(0-N个)

比如:

  • Binding Key 为“d.a.b”会同时路由到 Q1Q2
  • Binding Key 为“d.a.f”会路由到 Q1
  • Binding Key 为“c.e.f”会路由到 Q2
  • Binding Key 为“d.b.f”会被丢弃,或者返回给生产者(需要设置 mandatory)

创建队列和交换机

public static final String TOPIC_EXCHANGE = "topic.exchange";  
public static final String TOPIC_QUEUE1 = "topic.queue1";  
public static final String TOPIC_QUEUE2 = "topic.queue2";

生产者代码

和路由模式,发布订阅模式的区别是:交换机类型不同,绑定队列的 RoutingKey 不同

创建交换机

定义交换机类型为 BuiltinExchangeType.TOPIC

channel.exchangeDeclare(Constants.TOPIC_EXCHANGE, BuiltinExchangeType.TOPIC, true);

声明队列

channel.queueDeclare(Constants.TOPIC_QUEUE1, true, false, false, null);  
channel.queueDeclare(Constants.TOPIC_QUEUE2, true, false, false, null);

绑定交换机和队列

channel.queueBind(Constants.TOPIC_QUEUE1, Constants.TOPIC_EXCHANGE, "*.a.*");  
channel.queueBind(Constants.TOPIC_QUEUE2, Constants.TOPIC_EXCHANGE, "*.*.b");  
channel.queueBind(Constants.TOPIC_QUEUE2, Constants.TOPIC_EXCHANGE, "c.#");

发送消息

String msg_a = "hello topic, my routingkey is ae.a.f...";  
channel.basicPublish(Constants.TOPIC_EXCHANGE, "ae.a.f", null, msg_a.getBytes()); // 转发到 Q1  String msg_b = "hello topic, my routingkey is ef.a.b...";  
channel.basicPublish(Constants.TOPIC_EXCHANGE, "ef.a.b", null, msg_b.getBytes()); // 转发到 Q1 和 Q2  String msg_c = "hello topic, my routingkey is c.ef.d...";  
channel.basicPublish(Constants.TOPIC_EXCHANGE, "c.ef.d", null, msg_c.getBytes()); // 转发到 Q2

完整代码

package rabbitmq.topic;  import com.rabbitmq.client.BuiltinExchangeType;  
import com.rabbitmq.client.Channel;  
import com.rabbitmq.client.Connection;  
import com.rabbitmq.client.ConnectionFactory;  
import rabbitmq.constant.Constants;  import java.io.IOException;  
import java.util.concurrent.TimeoutException;  public class Producer {  public static void main(String[] args) throws IOException, TimeoutException {  //1. 建立连接  ConnectionFactory connectionFactory = new ConnectionFactory();  connectionFactory.setHost(Constants.HOST);  connectionFactory.setPort(Constants.PORT);  connectionFactory.setUsername(Constants.USER_NAME);  connectionFactory.setPassword(Constants.PASSWORD);  connectionFactory.setVirtualHost(Constants.VIRTUAL_HOST);  Connection connection = connectionFactory.newConnection();  //2. 开启信道  Channel channel = connection.createChannel();  //3.声明交换机  channel.exchangeDeclare(Constants.TOPIC_EXCHANGE, BuiltinExchangeType.TOPIC, true);  //4. 声明队列  channel.queueDeclare(Constants.TOPIC_QUEUE1, true, false, false, null);  channel.queueDeclare(Constants.TOPIC_QUEUE2, true, false, false, null);  //5. 绑定交换机和队列  channel.queueBind(Constants.TOPIC_QUEUE1, Constants.TOPIC_EXCHANGE, "*.a.*");  channel.queueBind(Constants.TOPIC_QUEUE2, Constants.TOPIC_EXCHANGE, "*.*.b");  channel.queueBind(Constants.TOPIC_QUEUE2, Constants.TOPIC_EXCHANGE, "c.#");  //6. 发送消息  String msg_a = "hello topic, my routingkey is ae.a.f...";  channel.basicPublish(Constants.TOPIC_EXCHANGE, "ae.a.f", null, msg_a.getBytes()); // 转发到 Q1  String msg_b = "hello topic, my routingkey is ef.a.b...";  channel.basicPublish(Constants.TOPIC_EXCHANGE, "ef.a.b", null, msg_b.getBytes()); // 转发到 Q1 和 Q2  String msg_c = "hello topic, my routingkey is c.ef.d...";  channel.basicPublish(Constants.TOPIC_EXCHANGE, "c.ef.d", null, msg_c.getBytes()); // 转发到 Q2  System.out.println("消息发送成功");  //7. 释放资源  channel.close();  connection.close();  }  
}

消费者代码

消费者代码和 Routing 模式的一样,只要修改消费队列的名称即可

  • 消费者 1
  • 消费者 2
package rabbitmq.topic;  import com.rabbitmq.client.*;  
import rabbitmq.constant.Constants;  import java.io.IOException;  
import java.util.concurrent.TimeoutException;  public class Consumer2 {  public static void main(String[] args) throws IOException, TimeoutException {  //1. 建立连接  ConnectionFactory connectionFactory = new ConnectionFactory();  connectionFactory.setHost(Constants.HOST);  connectionFactory.setPort(Constants.PORT);  connectionFactory.setUsername(Constants.USER_NAME);  connectionFactory.setPassword(Constants.PASSWORD);  connectionFactory.setVirtualHost(Constants.VIRTUAL_HOST);  Connection connection = connectionFactory.newConnection();  //2. 开启信道  Channel channel = connection.createChannel();  //3. 声明队列  channel.queueDeclare(Constants.TOPIC_QUEUE2, true, false, false, null);  //4. 消费消息  DefaultConsumer consumer = new DefaultConsumer(channel) {  @Override  public void handleDelivery(String consumerTag, Envelope envelope, AMQP.BasicProperties properties, byte[] body) throws IOException {  System.out.println("接收到消息:" + new String(body));  }  };  channel.basicConsume(Constants.TOPIC_QUEUE2, true, consumer);  }  
}

运行程序

启动生产者

image.png

  • 可以看到队列的消息数

启动消费者

  1. Consumer1
接收到消息:hello topic, my routingkey is ae.a.f...
接收到消息:hello topic, my routingkey is ef.a.b...
  1. Consumer2
接收到消息:hello topic, my routingkey is ef.a.b...
接收到消息:hello topic, my routingkey is c.ef.d...

http://www.hkcw.cn/article/mLYarGiOWx.shtml

相关文章

【RabbitMQ】RabbitMQ配置与交换机学习

文章目录 简介安装和部署1. 安装RabbitMQ2.创建virtual-host3. 添加依赖4.修改配置文件 WorkQueues模型1.编写消息发送测试类2.编写消息接收(监听)类3. 实现能者多劳 交换机Fanout交换机1.消息发送2.消息监听 Direct交换机1.消息发送2.消息接收 Topic交换…

详解RabbitMQ工作模式之发布订阅模式

目录 发布订阅模式 概念 概念介绍 特点和优势 应用场景 注意事项 代码案例 引入依赖 常量类 编写生产者代码 编写消费者1代码 运行代码 发布订阅模式 概念 RabbitMQ的发布订阅模式(Publish/Subscribe)是一种消息传递模式,它允许消…

Java操作RabbitMQ

文章目录 Spring集成RabbitMQ1. AMQP&SpringAMQP2. SpringBoot集成RabbitMQ3. 模型work模型 4.交换机Fanout交换机Direct交换机Topic交换机 5.声明式队列和交换机基于API声明基于注解声明 6.消息转换器 Spring集成RabbitMQ 1. AMQP&SpringAMQP AMQP(高级消…

女龙队从佛山九江“扒”向世界 农村大妈划出国际范

临近端午,广东多地的河道里又开始热闹起来,特别是佛山地区的龙舟活动历史悠久。九江镇被誉为全国首个龙舟名镇,赛龙舟的传统已有300年历史。九江是典型的水乡,河网密布,几乎每个村子都有河流经过,划船出行是最便捷的交通方式。在村民眼中,龙舟不仅能聚人气,还能增强村里…

同济大学教授路秉杰逝世 建筑学界痛失“中国塔王”

著名建筑历史学家、建筑教育家路秉杰先生因病医治无效,于2025年5月29日在上海逝世,享年90岁。他生前是中国建筑学会史学分会原副理事长,同济大学建筑与城市规划学院教授及博士生导师。路秉杰出生于1935年,山东聊城人。他在中日两国建筑史、园林史以及中国伊斯兰教建筑等领域…

武汉警界科技精英万松因公牺牲 幕后英雄悄然离去

5月27日0时33分,湖北省武汉市公安局科技信息化支队警务技术四级主任万松因公牺牲,享年50岁。两天后的早晨,武昌殡仪馆告别大厅内庄严肃穆,花圈环绕,哀乐低回。他的遗属、生前亲友及同事百余人含泪忍悲,送别这位警界科技精英。5月26日早上7时30分,青年民警王国栋送完孩子…

UniGUI DBGrid 实现多选

设置unidbgrid属性添加多选框 Options —> dgRowSelect、dgCheckSelect、dgMultiSelect —> True 属性完成后,保存运行,unidbgrid前面就会出现多选框,多选时质检选中前面的多选框或者 shift鼠标左键 将两次点击范围内的数据全选 或是 c…

常见位运算总结

位运算 常见位运算总结位1的个数比特位计数汉明距离只出现一次的数字 常见位运算总结 位1的个数 191. 位1的个数 给定一个正整数 n,编写一个函数,获取一个正整数的二进制形式并返回其二进制表达式中 设置位 的个数(也被称为汉明重量&#xf…

离散化算法的二分法应用

我们思考一个问题:其实这里的二分法回归本源也是基于下标映射的原理,只是实现是借助二分的形式。 在排序好的数组中对目标数值进行二分搜索,在 O(logn) 的时间复杂度内找到该数值是整体数据中的第几个。 具体的我们可以如下操作: …

字节流操作:InputStream类 读取文件的操作(三种 read 方法)

字节流操作:InputStream类 和 OutputStream类 文章目录 字节流操作:InputStream类 和 OutputStream类观前提醒:InputStream类 读取文件的操作(三种 read 方法)1. 不带参数的 read( )方法,返回值是&#xff…

day13 leetcode-hot100-22(链表1)

160. 相交链表 - 力扣(LeetCode) 1.哈希集合HashSet 思路 (1)将A链的所有数据存储到HashSet中。 (2)遍历B链,找到是否在A中存在。 具体代码 /*** Definition for singly-linked list.* pu…

《在人间》葛铮:以无言演绎孤独,肢体语言传递情绪

如何塑造一个全剧中几乎没有台词的角色?葛铮认为关键在于认真体验角色的内心,由心而发地去感受,在镜头前自然地表现。5月28日,他出演的高概念意象情感剧《在人间》播出,他在剧中饰演铁林一角,多数镜头中只能用肢体语言、面部表情等方式传递角色的情绪,这对葛铮来说无疑是…

【docker部署】 Windows版docker部署harbor镜像

个人简介:Java领域新星创作者;阿里云技术博主、星级博主、专家博主;正在Java学习的路上摸爬滚打,记录学习的过程~ 个人主页:.29.的博客 学习社区:进去逛一逛~ Windows版docker部署harbor镜像 Windows版dock…

TopCode之手撕快排

题目链接 912. 排序数组 - 力扣&#xff08;LeetCode&#xff09; 题目解析 算法原理 使用数组分三块的思想 i用来遍历整个数组 left用来标记<key的边界 right用来标记>key的边界 然后i进行遍历,数组就分成了四块 [l,left]<key [left1,i-1]key [i,right-1]未…

vue2使用node版本启动差异

node 14.21.3启动 无需添加去除ssl的环境变量&#xff0c;npm run dev即可 node 20.12.2 版本需要添加 SET NODE_OPTIONS–openssl-legacy-provider && "dev": "SET NODE_OPTIONS--openssl-legacy-provider && vue-cli-service serve"其…

母亲多种工具打孩子10多次被立案 强制报告制度显效

近日,司法部发布了一起未成年人法律援助典型案例。江苏省某小学老师发现学生胡某某身上有多处新旧伤痕,询问后得知胡某某因不愿意上学等问题被母亲多次殴打。老师随即按照强制报告制度要求向检察机关报告。经鉴定,胡某某挫伤面积达体表面积8%,已构成轻伤一级。随后,其母亲…

多家银行5年期定存利率跌破1.3% “存5年不如存1年”现象频现

离新一轮存款降息仅过去10天,部分中小银行存款利率开始出现剧烈调整。5月30日,多家农商行、村镇银行集体宣布下调定期存款利率。五年期整存整取利率最低降至1.20%,已低于六家国有大行、招商银行等大行1.30%的存款挂牌利率水平。“存5年不如存1年”这样的现象在中小银行中并不…

塞尔维亚一军工厂突发爆炸致7人受伤 工人制作炸药时意外引爆

当地时间30日早上7时40分,塞尔维亚军工企业“克鲁希克”位于瓦列沃市的工厂发生爆炸事故,导致7名工人受伤送医。伤者均为轻伤,已出院居家休养。事故发生在工人制作军用炸药过程中,压机上的引信被意外激活引发爆炸。有1名工人头部受伤,4人出现耳鸣症状。爆炸发生后厂区秩序…

专家解读印度“阵风”折翼背后较量 体系战斗力的较量

印巴冲突中,双方出动了大批战机进行猛烈交火。过去,印巴冲突多为地面战斗,而此次出现了大规模空中作战。这不仅是双方作战平台性能的直接较量,更是两国空战体系的深层碰撞。5月7日,印度武装部队发起代号为“朱砂”的行动,打击巴基斯坦和巴控克什米尔地区的设施。随后,巴…

长沙有花店将艾草花束卖到98元 节日氛围推高需求

端午节除了吃粽子,中国人还有在门口挂艾草的习俗。为了了解长沙市场上艾草的供应情况和价格,记者进行了走访。主打节日氛围的艾草出现在了超市和花店,经过商家精心搭配后成为一束束艾草花束。在河西的一家盒马超市内,摆放着多款艾草花束,价格从19.9元到39.9元不等。盒马相…