家人们!咱后端搬砖时,是不是总被 "同步 / 异步""MQ 咋用" 绕得脑壳疼?今天咱不整虚的,用 "点外卖、等快递" 的日常场景,把这些知识点嚼碎了喂你,最后还带手把手玩 RabbitMQ,看完直接上手不迷路!
一、先搞懂基础:同步 vs 异步,像 "打电话" vs "发微信"
咱先从最基础的 "通信方式" 说起,这俩货本质就是 "要不要等回复":
1. 同步通信:"喂?你收到没?没收到我再问一遍!"
就像你给外卖小哥打电话问 "我的炸鸡到哪了"------你必须等小哥说完(比如 "还有 5 分钟到"),才能挂电话干别的。
技术里就是:请求发出去后,调用方得一直等着对方处理完、返回结果,期间啥也干不了(阻塞)。
比如你写个userService.getUserId(),必须等数据库查完返回 ID,代码才能往下走。
👉 优点:简单直接,结果立等可取;缺点:一堵全堵,比如数据库卡了,整个接口都瘫了。
2. 异步通信:"消息发了,你看到回我就行~"
类似你给朋友发微信约饭 ------发完你该刷剧刷剧,朋友啥时候看到啥时候回,不耽误你干活。
技术里就是:请求发出去后,调用方不用等结果,直接走下一步,对方处理完再通过 "回调" 之类的方式通知你。
比如下单后发个消息 "订单创建成功",不用等库存扣减、物流发货完成,直接给用户返回 "下单成功",后续操作让其他系统慢慢搞。
👉 优点:不阻塞,系统抗造;缺点:需要中间件帮忙传消息(不然消息丢了咋整?),这就轮到 MQ 出场了!
二、MQ:后端的 "消息邮局",专治 "同步阻塞"
1. 啥是 MQ?就是 "帮你暂存消息的快递站"
你想给朋友寄零食,但朋友不在家 ------ 咋办?先放小区快递站,朋友回来自己取。
MQ(Message Queue)就是这个 "快递站":
- 发消息的一方(Producer):把 "零食"(消息)放进去;
- MQ 本身:暂存消息,保证不丢;
- 收消息的一方(Consumer):啥时候有空啥时候来取(或快递站主动送)。
2. MQ 的 3 个 "救命" 作用,后端必懂
解耦:比如电商下单,原来下单系统要直接调用库存、物流、积分系统 ------ 现在不用!下单系统只给 MQ 发个 "下单成功" 的消息,其他系统自己听 MQ,谁改了都不影响别人。
削峰:秒杀活动时,1 秒 10 万请求冲过来,数据库直接崩?让 MQ 先接着!系统按自己的节奏(比如每秒处理 1000)从 MQ 里拿请求,相当于 "用个桶接洪水,再慢慢放"。
异步:刚才说的 "下单不用等后续操作",就是靠 MQ 实现的,提升接口响应速度,用户再也不用等圈圈转半天。
3. 常见 MQ 大盘点:选哪个不踩坑?
咱后端常用的 MQ 就这几个,各有神通:
MQ 名字 | 特点(人话版) | 适合场景 |
---|---|---|
RabbitMQ | 老大哥,稳!支持多种协议,灵活 | 中小团队、需要高可靠性的场景(比如支付) |
Kafka | 吞吐量大到离谱,适合存大量日志 | 大数据、日志收集(比如 ELK 栈) |
RocketMQ | 阿里出品,抗造,适合电商秒杀 | 大公司、高并发业务(比如淘宝双 11) |
ActiveMQ | 老牌选手,功能全但有点老 | legacy 系统维护 |
三、重点突破:RabbitMQ 全家桶,从协议到配置
咱今天重点玩 RabbitMQ(毕竟灵活好上手,新手友好),先搞懂它的 "语言" 和 "工具":
RabbitMQ的架构中包含几个概念:
publisher
:生产者,也就是发送消息的应用程序consumer
:消费者,也就是消费消息的应用程序queue
:队列,存储消息的缓冲区。生产者投递的消息会暂存在消息队列中,等待消费者处理exchange
:交换机,负责消息路由。生产者发送的消息由交换机决定投递到哪个队列。virtual host
:虚拟主机,起到数据隔离的作用。每个虚拟主机相互独立,有各自的exchange、queue
1. AMQP 协议:RabbitMQ 的 "通用普通话"
你跟外国朋友聊天得用英语,不同系统跟 RabbitMQ 沟通,得用 AMQP 协议(Advanced Message Queuing Protocol)。
简单说:AMQP 规定了 "消息怎么发、怎么存、怎么收" 的规则,不管你是 Java、Python 还是 Go 写的系统,只要遵守这个规则,就能跟 RabbitMQ 顺畅沟通。
2. SpringAMQP:Spring 给 RabbitMQ 做的 "懒人工具包"
你直接用 RabbitMQ 原生 API,得写一堆连接、关闭的代码 ------ 麻烦!SpringAMQP 是 Spring 家族的 "专属插件",用注解就能搞定收发消息,不用管底层细节,后端 er 狂喜~
3. RabbitMQ 配置:3 步搞定,超简单
先把 RabbitMQ 跑起来,步骤如下(以 Windows 为例,Linux/mac 类似):
- 装依赖:RabbitMQ 依赖 Erlang,先装 Erlang(官网找对应版本,别瞎装!),再装 RabbitMQ。
- 启动 RabbitMQ:
- 打开命令行,输入rabbitmq-server start(Windows 可能要进 RabbitMQ 的 sbin 目录);
- 启动成功后,访问控制台:http://localhost:15672 ,默认账号密码都是guest(第一次登录会让你改密码,别忘啦)。
- 踩坑提醒:如果端口 15672 被占用,去 RabbitMQ 配置文件改端口;启动失败先查 Erlang 版本对不对。
四、实操:消息收发 3 种方式,手把手教你玩
消息收发的核心是 "交换机(Exchange)+ 队列(Queue)":交换机像 "快递分拣员",把消息分到对应的队列(快递柜),消费者从队列里拿消息。
咱分 3 种方式实现 "收发消息",从简单到代码级:
方式 1:RabbitMQ 控制台直接搞,不用写一行代码
适合新手体验,步骤如下:
- 登录控制台(http://localhost:15672 );

- 创建交换机:点 "Exchanges"→"Add a new exchange",名字随便写(比如test-exchange),类型选direct(简单模式),其他默认;
- 创建队列:点 "Queues"→"Add a new queue",名字写test-queue,其他默认;
- 绑定交换机和队列:在交换机详情页,"Bindings" 里填队列名test-queue,Routing Key 填test-key(相当于 "快递单号",要跟发消息时一致),点 "Bind";
- 发消息:交换机详情页 "Publish message",Routing Key 填test-key,Payload 写 "Hello RabbitMQ!",点 "Publish";
- 看消息:去队列详情页,点 "Get messages",就能看到刚才发的消息啦!
方式 2:消费者用 @RabbitListener,自动创建队列
实际开发中,咱不用手动建队列 ------ 让代码自动搞!用 SpringAMQP 的@RabbitListener注解:
- 加依赖(Maven):
xml
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-amqp</artifactId>
</dependency>
- 写消费者:
less
@Component
public class TestConsumer {
// 注解里指定队列名,项目启动时会自动创建这个队列
@RabbitListener(queuesToDeclare = @Queue(name = "test-queue2"))
public void receiveMsg(String msg) {
System.out.println("收到消息啦:" + msg);
}
}
- 写生产者(比如 Controller 里发消息):
kotlin
@RestController
public class TestProducer {
@Autowired
private RabbitTemplate rabbitTemplate;
@GetMapping("/send")
public String sendMsg() {
// 第一个参数:交换机(这里用默认交换机""),第二个:Routing Key(队列名),第三个:消息
rabbitTemplate.convertAndSend("", "test-queue2", "用@RabbitListener真方便!");
return "消息发出去啦~";
}
}
- 启动项目 :访问http://localhost:8080/send,控制台会打印 "收到消息啦:用 @RabbitListener 真方便!",队列也自动创建好了~
方式 3:生产者用 @Bean,手动声明交换机 + 队列
如果需要更灵活的配置(比如指定交换机类型、绑定规则),用@Bean在配置类里声明:
- 写配置类:
typescript
@Configuration
public class RabbitConfig {
// 1. 声明交换机
@Bean
public DirectExchange testExchange() {
// 交换机名、是否持久化(重启不丢)、是否自动删除
return new DirectExchange("test-exchange3", true, false);
}
// 2. 声明队列
@Bean
public Queue testQueue3() {
return QueueBuilder.durable("test-queue3").build(); // 持久化队列
}
// 3. 绑定交换机和队列
@Bean
public Binding bindingExchangeQueue(DirectExchange testExchange, Queue testQueue3) {
// Routing Key用"test-key3"
return BindingBuilder.bind(testQueue3).to(testExchange).with("test-key3");
}
}
- 发消息:
typescript
@GetMapping("/send3")
public String sendMsg3() {
// 这里要指定我们自己声明的交换机和Routing Key
rabbitTemplate.convertAndSend("test-exchange3", "test-key3", "用@Bean配置更灵活!");
return "消息发出去啦~";
}
- 收消息:还是用@RabbitListener(queues = "test-queue3"),启动后访问接口,就能收到消息啦~
五、补充:消息的 "推拉模式",该选哪个?
最后再唠唠消息怎么到消费者手里,分两种模式:
- 拉模式(Pull) :消费者主动去 MQ "要消息",比如 "每隔 10 秒去快递站看看有没有我的件"。
👉 适合:消费频率低的场景(比如每天凌晨统计数据),缺点是可能漏消息(没去要的时候消息到了)。
- 推模式(Push) :MQ 主动把消息 "推" 给消费者,比如 "快递员直接把件送上门"。
👉 适合:实时性高的场景(比如支付通知),缺点是如果消费者处理慢,会被 MQ "狂轰滥炸"(可以用限流解决)。
总结:看完就能上手的知识点
- 同步等回复,异步不阻塞,MQ 是中间 "快递站";
- RabbitMQ+SpringAMQP 是新手友好组合,AMQP 是 "通用语言";
- 收发消息 3 种方式:控制台手动搞、消费者 @RabbitListener、生产者 @Bean 配置;
- 推模式实时性高,拉模式适合低频场景。
赶紧动手试试!有啥坑或者疑问,评论区咱们唠~下次再深挖 RabbitMQ 的高级玩法(死信队列、延时队列这些),关注不迷路~