ReturnCallback 不触发需先设 mandatory=true 且配置 publisher-returns=true;exchange 不存在时不会进入该回调,而是触发异常或 ConfirmCallback。

ReturnCallback 不触发?先检查 mandatory 是否设为 true
ReturnCallback 本身不会自动生效,必须配合 mandatory = true 才能捕获“无法路由”的消息。如果只配置了回调但没开 mandatory,消息在交换机找不到匹配队列时会被静默丢弃,returnedMessage 根本不会被调用。
常见错误现象:日志里完全看不到回调输出,发一个错的 routingKey 或不存在的 exchange,也没有任何反应。
-
rabbitTemplate.setMandatory(true)必须在设置回调前或同时执行 - Spring Boot 2.1+ 推荐统一用
setReturnsCallback(函数式接口),而不是已废弃的setReturnCallback - 若使用
@Configuration初始化,建议放在@PostConstruct或ApplicationContextAware中确保RabbitTemplate实例已完全构建
Spring Boot 2.1+ 正确写法:用 setReturnsCallback + ReturnedMessage
旧版的 setReturnCallback 接收 5 个参数,容易记混顺序;新版 setReturnsCallback 只接收一个 ReturnedMessage 对象,字段更清晰、不易出错。IDE 里 returned.getExchange() 飘红,大概率是因为你还在用老接口,或者没导入正确类型。
实操建议:
- 确保依赖是 Spring AMQP 2.3+(对应 Spring Boot 2.5+)
- 回调中直接用
returned.getMessage().getBody()取原始字节,别忘了new String(...)转字符串 -
returned.getReplyCode()通常是312(NO_ROUTE),不是 HTTP 状态码,别和404混淆 - 示例代码:
rabbitTemplate.setReturnsCallback(returned -> {
log.warn("消息退回:exchange='{}', routingKey='{}', replyCode={}, replyText='{}'",
returned.getExchange(),
returned.getRoutingKey(),
returned.getReplyCode(),
returned.getReplyText());
// 这里可反序列化 message.getBody(),提取业务 ID 做补偿
});
配置文件里必须打开 publisher-returns
spring.rabbitmq.publisher-returns=true 是服务端开关,不配这个,Broker 根本不会把不可路由消息送回来,客户端再怎么设回调也没用。
开箱即用的技能链路由引擎。13 条预定义链覆盖搜索、开发、审查、MLOps、法律、创意等场景,三层路由架构(触发词→SAD反馈→DAG编排),recall@10=96.97%。配置驱动(chains.yaml),零代码扩展。pip install skill-weave-chains 一键安装。
注意几个易错点:
- 它和
publisher-confirm-type是独立配置,两者可以共存,但不能互相替代 -
publisher-returns在 Spring Boot 2.x 后不再叫publisher-returns的旧别名(如publisher-returns-enabled),只认这个精确键名 - 如果你用的是
CachingConnectionFactory,有些老版本需额外调用cachingConnectionFactory.setPublisherReturns(true) - YAML 示例:
spring:
rabbitmq:
publisher-returns: true
publisher-confirm-type: correlated
template:
mandatory: true
为什么 returned.getExchange() 返回 null?
这不是 bug,而是 RabbitMQ 协议行为:当发送时指定的 exchange 本身就不存在(比如拼错名字),Broker 会在 channel 层直接报错(AMQP NOT_FOUND),此时消息甚至没走到路由逻辑,ReturnCallback 不会触发 —— 触发的是连接异常或 ConfirmCallback 的失败回调(b == false)。
所以真正能进 ReturnedMessage 回调的,只有两类情况:
- exchange 存在,但所有绑定的 queue 都不匹配该
routingKey(典型 No Route) - exchange 是
direct或topic类型,且没有 queue 绑定到该 key - 如果想覆盖 exchange 不存在的场景,得靠
ConfirmCallback+ 异常捕获(例如AmqpIOException包含reply-code=404)
换句话说:getExchange() 有值,说明消息至少抵达了交换机;为 null,说明压根没到那一步 —— 别在 ReturnCallback 里查它。


















