文章目录
- [RabbitMQ Confirm 与 Return 消息确认机制](#RabbitMQ Confirm 与 Return 消息确认机制)
-
- 一、核心概念
-
- [1.1 Confirm 回调](#1.1 Confirm 回调)
- [1.2 Return 回调](#1.2 Return 回调)
- [1.3 两者关系](#1.3 两者关系)
- [二、YAML 配置](#二、YAML 配置)
- [三、三种 RabbitTemplate 配置](#三、三种 RabbitTemplate 配置)
-
- [3.1 配置类完整代码](#3.1 配置类完整代码)
- [3.2 三种模式对比](#3.2 三种模式对比)
- [四、Controller 注入](#四、Controller 注入)
-
- [4.1 构造函数注入](#4.1 构造函数注入)
- [4.2 注入说明](#4.2 注入说明)
- 五、四种发送模式演示
-
- [5.1 模式1:普通发送(无回调)](#5.1 模式1:普通发送(无回调))
- [5.2 模式2:Confirm 回调](#5.2 模式2:Confirm 回调)
- [5.3 模式3:Confirm + Return(正确路由)](#5.3 模式3:Confirm + Return(正确路由))
- [5.4 模式4:Confirm + Return(错误路由)](#5.4 模式4:Confirm + Return(错误路由))
- [六、CorrelationData 说明](#六、CorrelationData 说明)
-
- [6.1 作用](#6.1 作用)
- [6.2 correlationId 的用途](#6.2 correlationId 的用途)
- [6.3 使用示例](#6.3 使用示例)
- 七、流程说明
- 八、注意事项
- 九、总结
RabbitMQ Confirm 与 Return 消息确认机制
在 RabbitMQ 中,消息发送的可靠性 是生产环境的核心关注点。Spring AMQP 提供了两种回调机制:Confirm 回调 和 Return 回调,分别用于确认消息是否到达交换机、以及消息是否能正确路由到队列。
本文通过完整代码演示,说明三种配置模式的差异和使用场景。
一、核心概念
1.1 Confirm 回调
Confirm 回调用于确认消息是否成功到达交换机(Exchange)。
| 场景 | 回调结果 | 说明 |
|---|---|---|
| 消息到达交换机 | ack = true |
交换机已接收消息 |
| 消息未到达交换机 | ack = false |
交换机不存在或连接失败 |
注意:Confirm 回调只关心消息是否到达交换机,不关心消息是否被路由到队列。
1.2 Return 回调
Return 回调用于确认消息是否能正确路由到队列(Queue)。
| 场景 | 触发条件 |
|---|---|
| 消息无法路由到任何队列 | routingKey 不匹配、队列不存在等 |
前提 :必须设置
mandatory = true,否则消息会被直接丢弃。
1.3 两者关系
生产者 → 交换机 → 队列
↑ ↑
Confirm Return
(是否到达) (是否路由)
- Confirm:消息是否到达交换机
- Return:消息是否能路由到队列
- 两者独立,可单独或同时启用
二、YAML 配置
yaml
spring:
rabbitmq:
host: 192.168.1.100
port: 5672
username: study
password: study
virtual-host: test-virtual
publisher-confirm-type: correlated # 启用 Confirm 回调
publisher-returns: true # 启用 Return 回调
| 配置项 | 值 | 说明 |
|---|---|---|
publisher-confirm-type |
correlated |
启用异步 Confirm 回调 |
publisher-returns |
true |
启用 Return 回调 |
三、三种 RabbitTemplate 配置
3.1 配置类完整代码
java
@Configuration
public class RabbitTemplateConfig {
/**
* 模式1:无回调(默认)
* 适用于不需要确认的场景
*/
@Bean
@Primary
public RabbitTemplate rabbitTemplate(ConnectionFactory connectionFactory) {
return new RabbitTemplate(connectionFactory);
}
/**
* 模式2:Confirm 回调
* 消息是否到达交换机
*/
@Bean("rabbitTemplateConfirm")
public RabbitTemplate rabbitTemplateConfirm(ConnectionFactory connectionFactory) {
RabbitTemplate template = new RabbitTemplate(connectionFactory);
template.setConfirmCallback((correlationData, ack, cause) -> {
String correlationId = correlationData != null ? correlationData.getId() : "null";
if (ack) {
System.out.println("[Confirm] 消息到达交换机, correlationId=" + correlationId);
} else {
System.out.println("[Confirm] 消息未到达交换机, correlationId=" + correlationId + ", cause=" + cause);
}
});
return template;
}
/**
* 模式3:Confirm + Return 回调
* 消息是否到达交换机 + 是否能路由到队列
*/
@Bean("rabbitTemplateConfirmReturn")
public RabbitTemplate rabbitTemplateConfirmReturn(ConnectionFactory connectionFactory) {
RabbitTemplate template = new RabbitTemplate(connectionFactory);
template.setMandatory(true); // 必须设置,否则 Return 不触发
template.setConfirmCallback((correlationData, ack, cause) -> {
String correlationId = correlationData != null ? correlationData.getId() : "null";
if (ack) {
System.out.println("[Confirm+Return] 消息到达交换机, correlationId=" + correlationId);
} else {
System.out.println("[Confirm+Return] 消息未到达交换机, correlationId=" + correlationId + ", cause=" + cause);
}
});
template.setReturnsCallback(returned -> {
System.out.println("[Return] 消息无法路由到队列"
+ ", exchange=" + returned.getExchange()
+ ", routingKey=" + returned.getRoutingKey()
+ ", replyCode=" + returned.getReplyCode()
+ ", replyText=" + returned.getReplyText()
+ ", message=" + new String(returned.getMessage().getBody()));
});
return template;
}
}
3.2 三种模式对比
| 模式 | Bean 名称 | Confirm 回调 | Return 回调 | 适用场景 |
|---|---|---|---|---|
| 模式1 | rabbitTemplate |
❌ | ❌ | 不需要确认 |
| 模式2 | rabbitTemplateConfirm |
✅ | ❌ | 需要确认消息到达交换机 |
| 模式3 | rabbitTemplateConfirmReturn |
✅ | ✅ | 需要完整确认链路 |
四、Controller 注入
4.1 构造函数注入
java
@RestController
@RequestMapping("/confirm-demo")
public class ConfirmDemoController {
private final RabbitTemplate rabbitTemplate;
private final RabbitTemplate rabbitTemplateConfirm;
private final RabbitTemplate rabbitTemplateConfirmReturn;
public ConfirmDemoController(RabbitTemplate rabbitTemplate,
@Qualifier("rabbitTemplateConfirm") RabbitTemplate rabbitTemplateConfirm,
@Qualifier("rabbitTemplateConfirmReturn") RabbitTemplate rabbitTemplateConfirmReturn) {
this.rabbitTemplate = rabbitTemplate;
this.rabbitTemplateConfirm = rabbitTemplateConfirm;
this.rabbitTemplateConfirmReturn = rabbitTemplateConfirmReturn;
}
}
4.2 注入说明
| 参数 | 注解 | 说明 |
|---|---|---|
rabbitTemplate |
无 | 注入默认的 @Primary Bean |
rabbitTemplateConfirm |
@Qualifier("rabbitTemplateConfirm") |
指定注入 Confirm 回调的 Bean |
rabbitTemplateConfirmReturn |
@Qualifier("rabbitTemplateConfirmReturn") |
指定注入 Confirm+Return 回调的 Bean |
为什么不需要
@Autowired? Spring 4.3+ 如果类只有 1 个构造方法,会自动进行依赖注入。
五、四种发送模式演示
5.1 模式1:普通发送(无回调)
java
@GetMapping("/basic")
public String basic() {
CorrelationData correlationData = new CorrelationData(UUID.randomUUID().toString());
rabbitTemplate.convertAndSend(
RabbitMQConstants.EXCHANGE_NAME,
RabbitMQConstants.ROUTING_KEY,
"basic message",
correlationData);
return "已发送(basic),correlationId=" + correlationData.getId();
}
输出:无回调日志
5.2 模式2:Confirm 回调
java
@GetMapping("/confirm")
public String confirm() {
CorrelationData correlationData = new CorrelationData(UUID.randomUUID().toString());
rabbitTemplateConfirm.convertAndSend(
RabbitMQConstants.EXCHANGE_NAME,
RabbitMQConstants.ROUTING_KEY,
"confirm message",
correlationData);
return "已发送(confirm),correlationId=" + correlationData.getId();
}
输出:
[Confirm] 消息到达交换机, correlationId=550e8400-e29b-41d4-a716-446655440000
5.3 模式3:Confirm + Return(正确路由)
java
@GetMapping("/confirm-return")
public String confirmReturn() {
CorrelationData correlationData = new CorrelationData(UUID.randomUUID().toString());
rabbitTemplateConfirmReturn.convertAndSend(
RabbitMQConstants.EXCHANGE_NAME,
RabbitMQConstants.ROUTING_KEY,
"confirm-return message",
correlationData);
return "已发送(confirm-return),correlationId=" + correlationData.getId();
}
输出:
[Confirm+Return] 消息到达交换机, correlationId=550e8400-e29b-41d4-a716-446655440001
5.4 模式4:Confirm + Return(错误路由)
java
@GetMapping("/confirm-return-fail")
public String confirmReturnFail() {
CorrelationData correlationData = new CorrelationData(UUID.randomUUID().toString());
rabbitTemplateConfirmReturn.convertAndSend(
RabbitMQConstants.EXCHANGE_NAME,
"wrong-routing-key", // 错误的 routingKey
"confirm-return-fail message",
correlationData);
return "已发送(confirm-return-fail),correlationId=" + correlationData.getId();
}
输出:
[Confirm+Return] 消息到达交换机, correlationId=550e8400-e29b-41d4-a716-446655440002
[Return] 消息无法路由到队列, exchange=my-exchange, routingKey=wrong-routing-key, replyCode=312, replyText=NO_ROUTE, message=confirm-return-fail message
六、CorrelationData 说明
6.1 作用
CorrelationData 用于关联请求和响应,将发送的消息与 Confirm 回调关联起来。
java
CorrelationData correlationData = new CorrelationData(UUID.randomUUID().toString());
rabbitTemplate.convertAndSend(exchange, routingKey, message, correlationData);
6.2 correlationId 的用途
| 用途 | 说明 |
|---|---|
| 消息追踪 | 通过 correlationId 追踪消息的完整生命周期 |
| 日志关联 | 将发送日志和 Confirm 日志关联 |
| 业务关联 | 将消息与业务ID(如订单号)关联 |
6.3 使用示例
java
// 生成唯一ID
String orderId = "ORDER-" + System.currentTimeMillis();
CorrelationData correlationData = new CorrelationData(orderId);
// 发送消息
rabbitTemplate.convertAndSend(exchange, routingKey, message, correlationData);
// 在 Confirm 回调中使用
template.setConfirmCallback((data, ack, cause) -> {
String id = data.getId(); // 获取 orderId
if (ack) {
log.info("订单 {} 消息到达交换机", id);
} else {
log.error("订单 {} 消息发送失败: {}", id, cause);
}
});
七、流程说明

- 生产者发送消息到交换机
- Confirm 回调触发:确认消息是否到达交换机
- 消息路由:交换机根据 routingKey 将消息路由到队列
- Return 回调触发(如果设置了 mandatory):消息无法路由时触发
八、注意事项
-
mandatory 必须设置 :使用 Return 回调时,必须设置
template.setMandatory(true),否则消息会被丢弃而不触发 Return 回调。 -
Confirm 回调是异步的 :
publisher-confirm-type: correlated表示异步确认,消息发送后不会阻塞等待确认。 -
Return 回调在 Confirm 之后:Return 回调一定在 Confirm 回调之后触发,因为需要先确认消息到达交换机,才能判断是否能路由。
-
性能影响:Confirm 和 Return 回调会增加一定的性能开销,生产环境根据实际需求选择合适的模式。
-
异常处理:在回调方法中要做好异常处理,避免回调异常影响主流程。
九、总结
| 场景 | 推荐配置 |
|---|---|
| 不需要确认 | 模式1(无回调) |
| 需要确认消息到达交换机 | 模式2(Confirm) |
| 需要完整确认链路 | 模式3(Confirm + Return) |
| 关键业务(订单、支付) | 模式3 + 消息持久化 |
| 日志、监控等非关键业务 | 模式1 |
通过合理配置 Confirm 和 Return 回调,可以有效监控消息发送的可靠性,及时发现和处理消息丢失问题。