当前位置: 首页 > news >正文

rabbitmq学习demo,包含普通消息,TTL+死信队列,topic交换机三种情况,以项目形式讲解

mall-demo-mq

RabbitMQ 学习 Demo,通过 REST 接口手动触发不同 MQ 场景,观察控制台日志。项目源码在项目地址

项目结构

mall-demo-mq ├── pom.xml ├── README-MQ.md └── src/main ├── java/com/mtcarpenter/mall/demo/mq │ ├── MallDemoMqApplication.java # 启动类 │ ├── component │ │ └── RabbitMqDemoListener.java # 消费者监听器 │ ├── config │ │ └── RabbitMqDemoConfig.java # 交换机/队列/绑定/RabbitTemplate 配置 │ ├── constant │ │ └── MqDemoConstants.java # 交换机、队列、路由键常量 │ ├── controller │ │ └── DemoMqController.java # REST 入口,触发发送消息/创建订单 │ ├── domain │ │ ├── DemoOrder.java # 模拟订单实体 │ │ ├── DemoOrderStatus.java # 订单状态枚举 │ │ └── MqDemoMessage.java # 通用消息体 │ └── service │ ├── DemoOrderService.java # 模拟订单服务(内存 Map) │ └── RabbitMqDemoService.java # 生产者服务,封装消息发送逻辑 └── resources ├── application.yml # 端口、RabbitMQ 连接、手动 ack 等配置 └── static └── demo-mq-page.html # 浏览器交互页面

文件说明

文件说明
pom.xml项目依赖声明,parent 为spring-boot-starter-parent,依赖spring-boot-starter-webspring-boot-starter-amqp
MallDemoMqApplication.javaSpring Boot 启动类,@SpringBootApplication
RabbitMqDemoListener.java消费者,包含 4 个@RabbitListener方法,分别监听普通队列、订单取消队列、Topic 队列 A/B/C
RabbitMqDemoConfig.java声明所有交换机、队列、绑定关系;配置RabbitTemplate的 JSON 转换器、ConfirmCallback、ReturnCallback
MqDemoConstants.java集中定义交换机名、队列名、路由键名,方便查阅完整链路
DemoMqController.javaREST 接口入口,提供发送普通消息、无法路由消息、创建/支付/查询订单、发送 Topic 消息等接口
DemoOrder.java模拟订单 POJO,包含 orderId、status、timeoutSeconds、createTime、payTime、cancelTime
DemoOrderStatus.java订单状态枚举:WAIT_PAYPAIDCANCELED
MqDemoMessage.java通用消息体,包含 messageId、messageType、businessId、content、createdAt
DemoOrderService.java内存订单服务,用ConcurrentHashMap存储订单,提供创建、支付、超时取消、查询操作
RabbitMqDemoService.java生产者服务,封装 4 种发送方法:普通 direct、无法路由、订单延迟、Topic
application.yml端口 8088,RabbitMQ 连接本机,开启 publisher-confirms/returns,手动 ack,prefetch=1
demo-mq-page.html浏览器交互页面,点击按钮即可触发各接口,右侧显示响应结果

链路讲解

一、普通消息链路(Direct Exchange)

最基础的生产者 → 交换机 → 队列 → 消费者流程。

生产者 RabbitMQ 消费者 │ │ │ │ convertAndSend( │ │ │ demo.direct.exchange, │ │ │ demo.direct, │ │ │ message) │ │ │ ────────────────────────────► │ │ │ │ routing key = demo.direct │ │ │ 匹配绑定关系 │ │ │ ──────────────────────────────────► │ │ │ │ │ ◄── ConfirmCallback(ack=true)│ basicAck() │ │ │ ◄───────────────────────────────── │

关键资源:

类型名称说明
Exchangedemo.direct.exchangeDirect 类型,精确匹配 routing key
Queuedemo.direct.queue普通队列,无死信配置
Bindingrouting key =demo.direct交换机与队列的绑定关系

流程步骤:

  1. Controller 调用RabbitMqDemoService.sendDirectMessage()
  2. RabbitTemplate.convertAndSend()将消息发到demo.direct.exchange,routing key 为demo.direct
  3. 交换机根据 routing key 找到绑定队列demo.direct.queue,投递消息
  4. ConfirmCallback回调,ack=true表示消息已到达交换机
  5. RabbitMqDemoListener.handleDirectMessage()消费消息,手动basicAck

无法路由场景:使用 routing keydemo.no.queue发送,交换机能收到(ConfirmCallback ack=true),但找不到队列,触发ReturnCallback

易混洗点

Direct 交换机不局限于和队列一对一映射,核心匹配规则是消息的路由键必须与队列的绑定键完全相等。交换机承担消息中转的作用,只要存在匹配绑定关系的队列,就会将消息路由至对应队列。具体特性如下:

  1. 多个队列绑定相同绑定键时,这些队列都会接收到同一条消息;
  2. 一台 Direct 交换机可使用不同绑定键,分别绑定多个队列;
  3. 单个队列也可配置多个绑定键,以此接收不同路由键投递的消息。

二、TTL + 死信队列链路(订单超时取消)

利用消息 TTL 过期后自动转发到死信交换机,实现延迟消费。

生产者 RabbitMQ 消费者 │ │ │ │ convertAndSend( │ │ │ demo.order.delay.exchange│ │ │ demo.order.delay, │ │ │ message + TTL) │ │ │ ──────────────────────────► │ │ │ │ 消息进入 demo.order.delay.queue │ │ │ ── 等待 TTL 到期 ──► │ │ │ │ │ │ TTL 过期,消息变为死信 │ │ │ 死信转发到 demo.order.dead.exchange │ │ │ routing key = demo.order.cancel │ │ │ 投递到 demo.order.cancel.queue │ │ │ ────────────────────────────────────────► │ │ │ 查询订单状态 │ │ │ WAIT_PAY → CANCELED │ │ │ PAID → 跳过取消 │ │ │ basicAck() │ │ │ ◄──────────────────────────────────────── │

关键资源:

类型名称说明
Exchangedemo.order.delay.exchange延迟交换机,Direct 类型
Queuedemo.order.delay.queue延迟队列,配置了x-dead-letter-exchangex-dead-letter-routing-key无消费者监听
Exchangedemo.order.dead.exchange死信交换机,接收过期消息
Queuedemo.order.cancel.queue订单取消队列,消费者监听此队列
Bindingdelay 队列 → delay 交换机,routing key =demo.order.delay生产者投递入口
Bindingcancel 队列 → dead 交换机,routing key =demo.order.cancel死信投递出口

流程步骤:

  1. DemoOrderService.createOrder()创建订单(状态WAIT_PAY),调用RabbitMqDemoService.sendOrderTimeoutMessage()
  2. 消息设置expiration(毫秒级 TTL),发送到demo.order.delay.exchange
  3. 消息进入demo.order.delay.queue没有消费者监听,消息在此等待
  4. TTL 到期,RabbitMQ 将消息作为死信,按队列配置的x-dead-letter-exchange转发到demo.order.dead.exchange
  5. 死信交换机按x-dead-letter-routing-key=demo.order.cancel投递到demo.order.cancel.queue
  6. RabbitMqDemoListener.handleOrderTimeoutMessage()消费消息,调用DemoOrderService.cancelOrderIfStillWaitingPay()
  7. 幂等判断:只有WAIT_PAY状态才取消;PAID跳过;CANCELED跳过

核心思想:延迟队列只是"等待室",订单取消队列才是"处理室"。延迟消息只是提醒"该检查了",不能无脑取消。


三、Topic 交换机链路

Topic 交换机支持 routing key 的模式匹配:*匹配一个单词,#匹配零个或多个单词。

生产者 RabbitMQ 消费者 │ │ │ │ convertAndSend( │ │ │ demo.topic.exchange, │ │ │ topic.user.create, │ │ │ message) │ │ │ ────────────────────────────► │ │ │ │ topic.user.create 匹配结果: │ │ │ ┌─ topic.# ──► queue.a ──────────► │ 队列 A 消费者 │ │ └─ topic.user.* ──► queue.b ─────► │ 队列 B 消费者 │ │ │ │ │ topic.order.create 匹配结果: │ │ │ ┌─ topic.# ──► queue.a ──────────► │ 队列 A 消费者 │ │ └─ topic.order.create ──► queue.c ► │ 队列 C 消费者 │ │ │ │ │ topic.any.thing 匹配结果: │ │ │ └─ topic.# ──► queue.a ──────────► │ 队列 A 消费者

关键资源:

类型名称绑定模式说明
Exchangedemo.topic.exchangeTopic 类型交换机
Queuedemo.topic.queue.atopic.#匹配所有以topic.开头的路由键
Queuedemo.topic.queue.btopic.user.*只匹配topic.user.后跟一个单词
Queuedemo.topic.queue.ctopic.order.create精确匹配,效果等同于 Direct

路由匹配示例:

routing key队列 A (topic.#)队列 B (topic.user.*)队列 C (topic.order.create)
topic.user.create
topic.user.delete
topic.order.create
topic.any.thing
topic.user.a.b❌(*只匹配一个单词)

流程步骤:

  1. Controller 调用RabbitMqDemoService.sendTopicMessage(routingKey, content)
  2. 消息发送到demo.topic.exchange,携带用户指定的 routing key
  3. 交换机根据绑定模式逐一匹配,将消息投递到所有匹配的队列
  4. 各队列对应的@RabbitListener方法分别消费,手动basicAck

与 Direct 的区别:Direct 要求 routing key 完全相等;Topic 允许通配符,一条消息可同时投递到多个队列。

http://www.jsqmd.com/news/901490/

相关文章:

  • 告别复制粘贴:手把手教你用STM32CubeMX HAL库为8位8080 LCD屏写驱动(从引脚配置到地址计算)
  • 企业AI Agent的性能基准测试
  • 如何选北京二手房装修公司?2026年5月推荐TOP5评测厨卫改装防隐患案例特点注意事项 - 品牌推荐
  • 5G/6G混合光纤与FSO回传网络架构解析
  • 保姆级教程:给你的500G固态硬盘规划一个完美的Ubuntu 20.04双系统分区方案
  • 从桌面到服务器:Ubuntu系统升级的两种官方姿势(Software Updater vs do-release-upgrade)全解析
  • MATLAB图像处理实战:用HSV和YCbCr模型给你的照片换个“滤镜”(附完整代码)
  • 知识图谱:为AI助手构建关系型上下文,解决复杂决策难题
  • Linux多线程调试:别再只靠打印日志了,试试用pthread_setname_np给线程起个‘花名’
  • 2026年 广州消防泵最新推荐榜单:消防水泵/消防增压泵/立式消防泵/消防稳压泵/多级消防泵/XBD消防泵/消防喷淋泵/消防加压泵实力厂家精选! - 品牌企业推荐师(官方)
  • 零代码搭建你的第一个 AI Agent
  • 告别卡顿!手把手教你将TUM RGBD数据集tgz包转成30Hz流畅bag文件(附Python脚本)
  • Win11系统镜像怎么选?一篇讲清Dev/Beta/RP通道ISO的区别与适用场景
  • 进行信奥的比赛和训练,用开放的比如洛谷,AtCoder、CodeForces等题库好,还是用一些机构、学校或教练自己的内部题库好
  • AI增强编程实战:意图驱动开发与代码生成技术解析
  • 用Python实战检验时间序列的‘无记忆性’:以股票价格为例的马尔可夫性检验
  • TokCode:基于令牌重编码的语义通信抗丢包技术解析
  • 2026年5月中东专线物流公司推荐:TOP5评测专业价格适用场景 - 品牌推荐
  • 戴尔灵越5570亲测:Win11 dwm.exe吃内存?可能是你Intel核显驱动该更新了
  • SAP APO老兵实战复盘:从DP、SNP到PPDS,我们踩过的那些坑与S4HANA迁移实战指南
  • Word打不开报错0xc0000142?除了360和系统修复,这3个冷门但有效的排查思路你可能没想到
  • MCP协议安全漏洞深度解析:命令注入、SSRF与文件访问攻击的防御实践
  • 从信息论到代码:一文搞懂CrossEntropyLoss为何是分类任务的‘标配’
  • LibreCAD深度解析:开源2D CAD的全景透视与实战指南
  • 编译器与解释器区别详解
  • 【花雕学编程】Arduino BLDC 之机器人二维编队跟随(麦克纳姆轮底盘)
  • Wireshark 3.6.7 实战:5分钟从HTTPS流量里“抠”出SSL证书(附避坑指南)
  • 别再抱怨WPS卡了!实测教你手动关闭WPS常驻后台进程,瞬间释放几百M内存
  • 2026年5月北京二手房装修公司推荐:TOP5对比旧房改造防踩坑评测专业价格 - 品牌推荐
  • Prometheus告警怎么推送到钉钉?Alertmanager路由配置与多群分发实战