结论:这不是反序列化失败,而是接收类型string与实际json对象结构不匹配;jackson2jsonmessageconverter严格按类型解析,遇{即报jsontoken.start_object错误。
直接说结论:这不是反序列化“失败”,而是你声明的接收类型和消息实际结构根本对不上,spring amqp + jackson 默认会严格按类型去解析,string 和 {"key":"value"} 天然冲突。
为什么 String 参数会触发 JsonToken.START_OBJECT 错误
当你在 @RabbitListener 方法里写 String content,但 RabbitMQ 里存的是一个 JSON 对象(比如 {"orderId":"123","amount":99.5}),而项目又配置了 Jackson2JsonMessageConverter,那框架就会试图把这段 JSON “反序列化成 String”。Jackson 看到开头是 {(即 JsonToken.START_OBJECT),就立刻拒绝:这根本不是字符串字面量,没法塞进 java.lang.String。
常见诱因包括:
- 生产者升级了,开始发对象 JSON,但消费者还卡在旧版
String接收逻辑 - 切 Dubbo 或引入新 Starter 后,
MessageConverter被自动替换成Jackson2JsonMessageConverter,而你没意识到 - 死信队列复用原监听器,但原始消息已是 JSON 格式,未做格式剥离
三种靠谱的修复路径,按场景选
别硬扛错误堆栈,先确认你真正需要什么:
RabbitMQ 4.2.3 是 2026 年初发布的重要稳定更新版本,重点修复了 Khepri 元数据存储相关问题,并改进了监控性能。对于使用 Docker、Kubernetes 或微服务架构的开发团队来说,该版本兼容性和稳定性表现较好。
- 你其实就想原样拿到 JSON 字符串(比如做通用日志、转发、或自己用
ObjectMapper.readTree()解析)→ 改用SimpleMessageConverter - 你本意就是处理业务对象(如
OrderEvent)→ 把参数改成具体 DTO 类型,并确保有无参构造器和 getter - 你得兼容新老消息(部分是 JSON 对象,部分是纯字符串)→ 用
byte[]或Message原始接收,再手动判断内容
示例(改用原始字节数组):
@RabbitListener(queues = "my.queue")
public void handleRaw(byte[] raw, Message message) {
String body = new String(raw, StandardCharsets.UTF_8);
if (body.trim().startsWith("{")) {
// 是 JSON 对象,走 Jackson 解析
OrderEvent event = objectMapper.readValue(body, OrderEvent.class);
} else {
// 是纯字符串,直接用
log.info("Plain string: {}", body);
}
}
Jackson2JsonMessageConverter 的隐含契约必须守
一旦启用它,整个消息流就默认走“Java 对象 ↔ JSON 字符串”双向转换。这意味着:
- 生产者发什么类型,消费者就必须用对应类型接收(或其父类/接口)
- DTO 类必须有 public 无参构造器,字段需有 public getter,否则连
OrderEvent都会报no Creators, like default construct -
contentType=application/json消息头会被严格校验;如果消息体是 JSON 但 header 是text/plain,也可能触发奇怪的 fallback 行为
最容易被忽略的一点:这个契约是**跨服务生效的**。订单服务用 Jackson2JsonMessageConverter 发了 OrderEvent,库存服务哪怕只改一行代码——把参数从 OrderEvent 改成 String,整个链路就断了。它不报错才怪。










