家人们!咱用 RabbitMQ 时,是不是总被 “工作模型”“交换机绑定” 整懵?其实这些模型本质就是 “不同的消息配送方案”—— 今天用 “快递配送” 的日常场景,把 5 大模型嚼碎,再手把手教你 3 种声明方式,看完直接复制代码上手!
一、先搞懂核心:RabbitMQ 工作模型 =“快递配送方案”
RabbitMQ 的所有工作模型,都围绕 “交换机(分拣站)+ 队列(快递柜)+ 生产者(寄件人)+ 消费者(收件人)” 这四件套。不同模型,就是 “分拣站怎么把快递分到快递柜” 的不同规则 —— 咱逐个看:
1. Basic Queue:简单模式 =“个人寄快递,一对一送”
类比场景
你给朋友寄一箱零食,直接写朋友地址,快递员只送这一个收件人 ——一个生产者发消息,一个消费者收消息,一对一专属配送。
原理拆解
- 没有复杂交换机!生产者直接把消息扔到 “Basic Queue” 队列;
- 消费者盯着这个队列,消息一到就拿走处理;
- 特点:简单直接,适合 “单一任务处理”(比如下单后发一条短信通知)。
代码小片段(SpringAMQP)
// 生产者发消息(直接指定队列名)
@GetMapping("/send-simple")
public String sendSimple() {
rabbitTemplate.convertAndSend("basic-queue", "这是简单模式的消息~");
return "消息发送成功!";
}
// 消费者收消息(监听指定队列)
@RabbitListener(queues = "basic-queue")
public void receiveSimple(String msg) {
System.out.println("收到简单模式消息:" + msg);
}
2. 广播模式(Publish/Subscribe)=“小区群发通知,人人有份”
类比场景
小区物业发 “停水通知”,所有业主都要收到 ——一个生产者发消息,多个消费者同时收到,消息像广播一样扩散。
原理拆解
- 必须用 “Fanout 交换机”(像小区公告栏,贴上去的通知所有人能看);
- 所有队列都绑定到这个 Fanout 交换机;
- 生产者把消息发给 Fanout 交换机,交换机会把消息 “复制” 到所有绑定的队列,每个消费者都能拿到完整消息;
- 特点:消息不重复,每个消费者都能收到,适合 “群发通知”(比如系统维护通知、订单状态同步给多个下游系统)。
关键:队列绑定交换机
// 用@Bean声明Fanout交换机+2个队列+绑定关系
@Bean
public FanoutExchange fanoutExchange() {
return new FanoutExchange("test-fanout-exchange");
}
@Bean
public Queue fanoutQueue1() { return new Queue("fanout-queue1"); }
@Bean
public Queue fanoutQueue2() { return new Queue("fanout-queue2"); }
// 绑定队列1到交换机
@Bean
public Binding bindingFanout1(FanoutExchange fanoutExchange, Queue fanoutQueue1) {
return BindingBuilder.bind(fanoutQueue1).to(fanoutExchange);
}
// 绑定队列2到交换机
@Bean
public Binding bindingFanout2(FanoutExchange fanoutExchange, Queue fanoutQueue2) {
return BindingBuilder.bind(fanoutQueue2).to(fanoutExchange);
}
3. Routing 模式 =“按地址分区送快递,精准匹配”
类比场景
快递公司送件时,“北京朝阳区” 的快递只送朝阳网点,“上海浦东” 的只送浦东网点 ——消息带 “路由键(Routing Key)”,只有队列的绑定键和它完全匹配,才能收到消息。
原理拆解
- 用 “Direct 交换机”(像快递分拣系统,按地址关键词分拣);
- 队列绑定交换机时,要指定 “绑定键(Binding Key)”(比如 “order.pay”);
- 生产者发消息时,要指定 “路由键(Routing Key)”(比如 “order.pay”);
- 只有路由键 = 绑定键,消息才会进入对应队列;
- 特点:精准匹配,适合 “按类型分发消息”(比如订单系统,支付成功发 “order.pay”,退款成功发 “order.refund”,不同队列处理)。
4. Topics 模式 =“按关键词模糊匹配,更灵活”
类比场景
快递公司送 “生鲜食品”,不管是 “北京朝阳生鲜” 还是 “上海浦东生鲜”,都统一送 “生鲜专属网点”——用通配符模糊匹配路由键,比 Routing 模式更灵活。
原理拆解
- 用 “Topic 交换机”(支持通配符的分拣系统);
- 绑定键支持两个通配符:
-
- :匹配 1 个单词(比如 “order.” 能匹配 “order.pay”“order.refund”,但不能匹配 “order.pay.success”);
-
- #:匹配 0 个或多个单词(比如 “order.#” 能匹配 “order.pay”“order.pay.success”);
- 生产者发消息带路由键,交换机按通配符匹配绑定键,把消息分发到对应队列;
- 特点:灵活适配多种场景,适合 “复杂分类”(比如日志系统,“log.error”“log.warn”“log.info”,用 “log.#” 绑定所有日志队列)。
5. RPC 模式 =“寄重要文件,要收件人签收回执”
类比场景
你寄一份合同,需要对方签收后给你回个 “已收到” 的短信 ——生产者发消息后,需要等待消费者处理完,返回 “响应消息”,像远程调用(RPC)一样。
原理拆解
- 流程比其他模式多一步:
- 生产者发 “请求消息” 到队列,同时创建一个 “临时响应队列”,等待回复;
- 消费者从队列拿 “请求消息”,处理完后,把 “响应消息” 发回生产者的临时队列;
- 生产者从临时队列拿到响应,完成一次 “调用 - 响应”;
- 特点:需要同步等结果,适合 “需要返回值的场景”(比如远程查询用户信息,需要拿到用户数据再继续处理);
- 踩坑提醒:别滥用!RabbitMQ 主打异步,RPC 模式会增加复杂度,能不用就不用。
二、3 种声明方式:队列 & 交换机怎么建?选对不踩坑
搞懂模型后,关键是 “怎么创建交换机和队列”?3 种方式各有适用场景,咱逐个说:
方式 1:控制台手动创建 ——“偶尔跑腿,不常用”
操作步骤
- 登录 RabbitMQ 控制台(http://localhost:15672 );
- 建交换机:点 “Exchanges”→填名字 + 选类型(Fanout/Direct/Topic)→“Add exchange”;
- 建队列:点 “Queues”→填名字→“Add queue”;
- 绑定:在交换机详情页,填队列名 + 绑定键→“Bind”。
优缺点
- 优点:不用改代码,临时测试方便;
- 缺点:每次环境部署都要手动建,容易漏建 / 建错,生产环境绝对不用!
方式 2:@Bean 声明 ——“提前备好,服务启动自动建”
核心逻辑
在 Spring 配置类里,用@Bean声明交换机、队列、绑定关系,项目启动时,SpringAMQP 会自动在 RabbitMQ 里创建这些资源(如果不存在)。
代码示例(Topic 模式)
@Configuration
public class RabbitTopicConfig {
// 1. 声明Topic交换机
@Bean
public TopicExchange topicExchange() {
// 交换机名、是否持久化(重启不丢)、是否自动删除
return new TopicExchange("test-topic-exchange", true, false);
}
// 2. 声明队列
@Bean
public Queue topicQueue1() {
return QueueBuilder.durable("topic-queue1").build(); // 持久化队列
}
// 3. 绑定队列到交换机(绑定键:order.#)
@Bean
public Binding bindingTopic1(TopicExchange topicExchange, Queue topicQueue1) {
return BindingBuilder.bind(topicQueue1).to(topicExchange).with("order.#");
}
}
适用场景
- 固定的绑定关系(比如系统核心的交换机和队列);
- 适合在配置类里统一管理,服务启动就就绪,稳定可靠。
方式 3:@RabbitListener 声明 ——“消费者自己搞定,复杂绑定也不怕”
核心逻辑
不用单独写配置类,直接在消费者方法上用@RabbitListener,注解里直接声明交换机、队列、绑定关系,项目启动时自动创建。
代码示例(广播模式)
// 消费者方法上直接声明Fanout交换机+队列+绑定
@RabbitListener(bindings = @QueueBinding(
value = @Queue(name = "listener-fanout-queue", durable = "true"), // 队列(持久化)
exchange = @Exchange(name = "listener-fanout-exchange", type = ExchangeTypes.FANOUT), // 交换机(Fanout类型)
key = "" // Fanout模式不用绑定键,填空
))
public void receiveFanoutByListener(String msg) {
System.out.println("收到@RabbitListener声明的广播消息:" + msg);
}
适用场景
- 复杂的绑定关系(比如一个消费者需要绑定多个交换机);
- 消费者和队列强关联的场景(比如某个服务专属的队列,跟着服务代码走,不用单独管理配置)。
总结:看完就能用的 RabbitMQ 指南
- 五大模型记类比:简单 = 一对一,广播 = 群发,Routing = 精准匹配,Topics = 模糊匹配,RPC = 要回执;
- 三种声明看场景:控制台临时用,@Bean 统一配,@RabbitListener 灵活搞;
- 新手先从 “简单模式 +@RabbitListener” 上手,熟悉后再玩 Topics 和 Routing。
赶紧动手试试!遇到坑或者有更有趣的类比,评论区咱唠~下次再深挖 RabbitMQ 的高级玩法(死信队列、延时队列),关注不迷路~