一、AMQP 与 Spring AMQP
(一)AMQP 协议简介
AMQP(Advanced Message Queuing Protocol,高级消息队列协议) 是一种用于在应用程序之间传递业务消息的 开放标准协议。
它的核心特点包括:
**与编程语言无关:**Java、Python、Go、C# 等都可以基于 AMQP 进行通信
**与平台无关:**不依赖具体操作系统或运行环境
**解耦系统组件:**生产者与消费者无需直接通信
**天然适合微服务架构:**符合服务自治、松耦合的设计思想
在微服务或分布式系统中,AMQP 常用于:
服务之间的异步通信
削峰填谷(应对突发流量)
系统解耦与可靠消息传递
RabbitMQ 正是 AMQP 协议最经典、最成熟的实现之一。
(二)Spring AMQP 简介
Spring AMQP 是 Spring 官方基于 AMQP 协议提供的一套消息中间件解决方案,用于简化 AMQP 在 Spring 应用中的使用。
Spring AMQP 并不是一个消息队列,而是一个 对 AMQP 协议的 Java 抽象与封装,主要包含两个核心模块:
spring-amqp
定义了 AMQP 的核心抽象接口(Message、Exchange、Queue、Template 等)
与具体消息中间件实现解耦
spring-rabbit
spring-amqp 的默认实现
基于 RabbitMQ Java Client
负责与 RabbitMQ 服务端进行真正的网络通信
在实际开发中:
我们面向 Spring AMQP 的 API 编程
由 spring-rabbit 在底层完成与 RabbitMQ 的交互
这也是 Spring 生态一贯的设计思想:
面向接口编程,屏蔽底层实现细节,提升开发效率。
二、实践
(一)快速掌握 Spring AMQP 的基本使用方式
1. 实践目标
本实践通过一个最简单的 RabbitMQ 队列模型,快速掌握 Spring AMQP 的基本使用方式,具体目标如下:
通过 RabbitMQ 控制台 手动创建队列 simple.queue
在 publisher 服务 中,使用 RabbitTemplate 向队列发送消息
在 consumer 服务 中,使用 @RabbitListener 监听并消费队列消息
整体结构清晰、步骤完整,适合作为 Spring AMQP 的入门示例。
2. 创建队列 simple.queue
**(1)**创建普通用户
根据前一篇文章的步骤,新建一个 RabbitMQ 用户:
用户名:xiaoman 密码:1007 用户角色:management
说明:
management 权限 即可登录控制台并管理队列
不需要 administrator 权限

(2) 登录控制台并创建队列
浏览器访问:
java
http://192.168.41.136:15672
使用 xiaoman 用户登录
进入 Queues 页面
新建队列:
Queue name:simple.queue
其他参数保持默认
队列创建完成后,可在列表中看到 simple.queue。

3. 创建项目并引入依赖
(1)项目结构
创建一个 Maven 父工程:
java
rabbitmq_practice
├── publisher # 消息生产者
└── consumer # 消息消费者
(2) 父工程 pom.xml
在 rabbitmq_practice 的 pom.xml 中统一管理依赖:
java
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.7.18</version>
</parent>
<dependencies>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
</dependency>
<!-- AMQP 依赖 ,包含RabbitMQ-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-amqp</artifactId>
</dependency>
<!-- 单元测试 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
</dependency>

子工程 publisher 和 consumer 继承该父工程即可。
4. 配置 RabbitMQ 连接信息
在 publisher 和 consumer 的 application.yml 中,配置 RabbitMQ 服务端信息:
java
spring:
rabbitmq:
host: 192.168.41.136
port: 5672
virtual-host: /
username: xiaoman
password: 1007

说明:
两个服务连接的是 同一个 RabbitMQ
使用同一个虚拟主机 /
5. 发送消息(publisher)
Spring AMQP 提供了 RabbitTemplate,用于简化消息发送操作。
(1)编写测试类
在 publisher 模块中创建测试类:
java
@SpringBootTest
public class SpringAmqpTest {
@Autowired
private RabbitTemplate rabbitTemplate;
@Test
void testSendMessageQueue(){
String queueName = "simple.queue";
String msg = "hello, amqp";
rabbitTemplate.convertAndSend(queueName, msg);
}
}
(2) 运行测试
运行测试方法后:
消息会被发送到 simple.queue
在 RabbitMQ 控制台中可看到 Ready 数量增加
此时也可以手动点击 Get Message(s) 查看消息内容。



6. 接收消息(consumer)
(1)启动类
在 consumer 模块中创建启动类:
java
@SpringBootApplication
public class ConsumerApplication {
public static void main(String[] args) {
SpringApplication.run(ConsumerApplication.class,args);
}
}

(2)编写消费者监听器
使用 @RabbitListener 声明式监听队列:
java
@Slf4j
@Component
public class SimpleQueueListener {
@RabbitListener(queues = "simple.queue")
public void listenerSimpleQueue(String msg){
System.out.println("消费者收到消息的simple.queue的消息:" + msg);
}
}

(3)启动消费者
启动 ConsumerApplication 后:
Spring AMQP 会自动监听 simple.queue
当队列中有消息时,方法会被自动调用
控制台会打印接收到的消息内容

说明:
消息成功从 publisher 发送
被 consumer 正常消费
三、WorkQueue模式
Work Queue 用于 模拟多个消费者共同消费同一个队列中的任务,典型应用场景包括:
异步任务处理(如订单、日志、短信)
后台任务削峰
提升系统整体吞吐量
其核心目标是:
一个队列,多个消费者,任务被"分摊"执行,而不是被重复消费。
(一)实践目标
通过实验观察并理解:
RabbitMQ 默认的 Work Queue 分发策略
不同消费能力的消费者在默认模式下的表现
如何通过 prefetch(公平调度) 优化任务分配
实验设计如下:
-
创建队列 work.queue
-
publisher 在 1 秒内发送 50 条消息
-
consumer 中定义 两个消费者同时监听同一队列
-
消费者 1:快(≈ 每秒 50 条)
-
消费者 2:慢(≈ 每秒 5 条)
(二)创建队列 work.queue
通过 RabbitMQ 管理控制台创建队列:
Queue Name:work.queue
其他参数保持默认

(三)publisher 发送 50 条消息(1 秒内)
在 publisher 测试类中编写如下方法:
java
@Test
void sendWorkQueueMessage() throws InterruptedException {
String queueName = "work.queue";
for (int i = 1; i <= 50; i++ ){
String msg = "任务消息: " + i;
rabbitTemplate.convertAndSend(queueName, msg);
Thread.sleep(20);
}
System.out.println("50 条消息发送完成");
}

(四)consumer:定义两个不同处理能力的消费者
这里通过 两个监听方法,模拟两个独立消费者。
消费者 1:处理快(≈ 每秒 50 条)
思路说明:
每条消息处理耗时 ≈ 20ms
1 秒可处理约 50 条
java
@Slf4j
@Component
public class WorkQueueConsumer1 {
@RabbitListener(queues = "work.queue")
public void handleMessage(String msg) throws InterruptedException {
// 模拟快消费者
Thread.sleep(20);
System.out.println("【消费者1-快】处理消息:" + msg);
}
}

消费者 2:处理慢(≈ 每秒 5 条)
思路说明:
每条消息处理耗时 ≈ 200ms
1 秒只能处理 5 条
java
@Slf4j
@Component
public class WorkQueueConsumer2 {
@RabbitListener(queues = "work.queue")
public void handleMessage(String msg) throws InterruptedException {
// 模拟慢消费者
Thread.sleep(200);
System.out.println("【消费者2-慢】处理消息:" + msg);
}
}

(五)默认模式运行现象(轮询分发)
运行步骤
-
启动 consumer 服务
-
执行 publisher 测试方法
现象观察
按直觉:
消费者 1 更快,应该消费更多消息
但实际结果是:
两个消费者 几乎各消费一半消息
慢消费者明显"拖慢"整体处理速度


原因分析
RabbitMQ 默认采用轮询(Round-Robin)分发策略:
不关心消费者处理速度
只按"消费者数量"平均分发消息
这正是 Work Queue 默认模式下最容易踩的一个"坑"。
(六)Work Queue 的核心:公平调度(Prefetch)
为了避免慢消费者拖垮系统,需要开启 公平调度机制。
其思想是:
谁处理得快,谁就多拿任务;处理慢的消费者自动少拿。
1. 配置 prefetch
在 application.yml 中添加配置:
java
listener:
simple:
prefetch: 1
acknowledge-mode: auto

2. 参数含义说明
prefetch: 1
每个消费者 同一时刻最多只持有 1 条未确认消息
acknowledge-mode: auto
消费成功 → 自动 ACK
消费异常 → 自动 NACK
**(七)**开启公平调度后的效果
重新启动 consumer,再次发送消息,可以明显观察到:
快消费者不断收到新消息
慢消费者处理完一条后,很久才拿到下一条
消息分配明显 倾向处理快的一方


(八)为什么这才是真正的"公平"?
| 对比项 | 默认模式 | prefetch = 1 |
|---|---|---|
| 分发依据 | 消费者数量 | 消费者处理能力 |
| 慢消费者 | 仍然分到一半 | 自动降权 |
| 快消费者 | 被拖慢 | 多劳多得 |
| 系统吞吐 | 低 | 高 |
公平 ≠ 平均 公平 = 谁快谁多拿
Work Queue 的公平调度,本质上是通过 限制未确认消息数量,让 RabbitMQ 能够根据消费者的实时处理能力动态分配任务,从而显著提升整体吞吐量与系统效率。
四、总结
本文从 AMQP 协议的基本概念出发,介绍了 Spring AMQP 在 Spring 生态中的定位与作用,并通过完整的实践示例,演示了 Spring Boot 如何快速集成 RabbitMQ。
在实践部分,我们首先通过最简单的 Simple Queue 模式,掌握了消息发送与接收的基本流程,包括队列创建、RabbitTemplate 发送消息以及 @RabbitListener 消费消息。在此基础上,进一步引入 Work Queue 模式,通过多个消费者共同消费同一队列中的任务,直观地观察了 RabbitMQ 默认分发策略在不同消费能力下的表现。
最后,通过对 Work Queue 场景的分析,引出了 prefetch(公平调度) 的概念,为后续理解消息积压、消费均衡以及高并发场景下的消息处理优化打下基础。
通过这些实践,可以清晰地体会到消息队列在 系统解耦、异步处理与削峰填谷 等场景中的价值,也为在微服务架构中更合理地使用 RabbitMQ 提供了实践参考。