RabbitMQ跨服务传对象因包名不同引发ClassNotFoundException问题
两个服务通过RabbitMQ互相发送基于Jackson多态序列化的对象,父类定义如下:
@JsonTypeInfo(use = JsonTypeInfo.Id.NAME, property = "type", visible = true) @JsonSubTypes({ @JsonSubTypes.Type(value = Subclass.class, name = "Subclass") }) public abstract class ParentClass implements Serializable {...}
发送端生成的RabbitMQ消息包含以下内容:
__TypeId__: sending.service.package.Subclass content_encoding: UTF-8 content_type: application/json Payload {"type":"Subclass", etc}
接收端存在同名但包名不同的Subclass,接收消息时触发sending.service.package.Subclass的ClassNotFoundException。预期中Jackson的@JsonTypeInfo和@JsonSubTypes应该使用Payload中的type字段匹配子类,但实际消息转换器却使用了RabbitMQ消息头中的__TypeId__字段。接收端监听代码如下:
@RabbitListener(queues = ParentClassConfig.QUEUE_NAME) public void handleParentClass(final @Payload ParentClass parentClass) { // 处理逻辑 }
已尝试通过ObjectMapper注册子类、开启NON_CONCRETE_AND_ARRAYS类型默认处理,但均无效。
问题原因
Spring AMQP默认使用的Jackson2JsonMessageConverter会优先读取RabbitMQ消息头中的__TypeId__字段来确定反序列化目标类型,而非完全依赖Jackson自身的@JsonTypeInfo配置。发送端发送消息时,该转换器会自动将发送类的全限定类名写入__TypeId__头,接收端尝试加载这个跨包的类时就会抛出ClassNotFoundException。
解决方案
1. 禁用__TypeId__头的类型解析
自定义Jackson2JsonMessageConverter,通过设置setTypeIdPropertyName(null)让转换器忽略消息头的类型信息,完全依赖Payload中的type字段进行Jackson多态匹配:
@Bean public MessageConverter jackson2JsonMessageConverter() { Jackson2JsonMessageConverter converter = new Jackson2JsonMessageConverter(); // 禁用消息头的类型解析,转而使用Jackson的@JsonTypeInfo配置 converter.setTypeIdPropertyName(null); return converter; }
也可以将typeIdPropertyName设置为你在@JsonTypeInfo中定义的type字段,让转换器同步使用该字段,但直接禁用头解析更贴合你的需求。
2. 确保两端Jackson多态配置一致
发送端和接收端的ParentClass上的@JsonSubTypes配置必须完全匹配:
- 两端的
name值要一致(比如都为"Subclass") - 各自的
value指向自身包下的Subclass类
这样Jackson在解析Payload中的type字段时,能正确映射到接收端本地的子类。
内容的提问来源于stack exchange,提问作者Wouter Zelle

