标签:Springboot Rabbitmq MessageConversionException
话不多说,先看错误截图。

报错原因是说类型转换错误。找不到对应的类。我发现这个类“MessageDto”是发送方定义的实体类,我作为接收方没有引用对方的实体类。难道必须要引入发送方的实体,那不是明显不符合MQ解耦的原则啊。应该是哪里配置错了。我查看了发送方的RabbitMq的配置。


注意到发送方配置了一个MessageConverter,用的是Jackson2JsonMessageConverter。发送消息的代码如下
bpRabbitTemplate.convertAndSend(exchange, null, message);
点击查看源码发现(RabbitTemplate实体类型)
public void convertAndSend(String exchange, String routingKey, final Object object, CorrelationData correlationData)throws AmqpException {
send(exchange, routingKey, convertMessageIfNecessary(object), correlationData);
}
找到convertMessageIfNecessary,继续查看
protected MessageconvertMessageIfNecessary(final Object object) {
if (objectinstanceof Message) {
return (Message) object;
}
return getRequiredMessageConverter().toMessage(object, new MessageProperties());
}
发现getRequiredMessageConverter()这段代码就是获取我们配置的MessageConverter,即Jackson2JsonMessageConverter。继续深入查看toMessage()方法。 ps:在类AbstractMessageConverter中。

关注createMessage(),这是个抽象方法,由子类提供实现。我们进入Jackson2JsonMessageConverter类的实现,找到如下代码

点击进去发现这段代码,
addHeader(properties, getClassIdFieldName(), javaType.getRawClass());
查看getClassIdFieldName()发现
public static final String DEFAULT_CLASSID_FIELD_NAME = "__TypeId__";
是不是很眼熟,对,开头错误截图里面。默认的Jackson2JsonMessageConverter在发送消息的时候都会在header中记录发送消息的实体类信息,类似“XXX.XXX.XXX.producer.mq.MessageDto”。看到这里我们不禁会想,接收到消息的时候会不会也用到这个“TypeId”,反射生成一个这个类呢?如果这个类不在我们的代码库中,是不是就报错了?
继续查看Jackson2JsonMessageConverter的fromMessage()方法

找到toJavaType()方法中,
看到这两段代码
//找到MessageProperties的header中的_TypeId_,拿到需要实例化的实体类名称
String typeIdHeader = retrieveHeaderAsString(properties, getClassIdFieldName());
JavaType contentClassType = getClassIdType(retrieveHeader(properties, getContentClassIdFieldName()));

这段代码是不是也很熟悉,在错误日志截图里面。跟我们猜测的一样。如果发送方和接收方都用Jackson2JsonMessageConverter的,那它接收到消息的时候会根据发送方的实体类进行序列化,如果接收方没有这个实体类就会报错。所以到这里解决方案就出来了。
方法1:抽取一个公用的依赖包,发送方和接收方都引入统一的实体类。按照上述的配置不动即可。
方法2:发送方配置不动,修改接收方的配置,我们接收方不采用Jackson2JsonMessageConverter即可。看下我最新的配置

但是这样改之后发现还是不行,为什么呢?AbstractAdaptableMessageListener默认的就是
private MessageConverter messageConverter = new SimpleMessageConverter();
这个转换器啊。其实问题出现在这段代码上
@Bean public MessageConverter jackson2JsonMessageConverter() { Jackson2JsonMessageConverter messageConverter = new Jackson2JsonMessageConverter(); return messageConverter; }
因为是在@Configuration使用 @Bean的,所有@Bean实例化的Bean是存在于spring上下文中的。而AbstractAdaptableMessageListener在有定义getter和setter messageConverter的方法。很自然的会替换AbstractAdaptableMessageListener默认的SimpleMessageConverter。使用显示声明的Bean.
@Configuration 注释位于类的顶端。它告知 Spring 容器这个类是一个拥有 bean 定义和依赖项的配置类。@Bean 注释用于定义 bean。上述注释位于实例化 bean 并设置依赖项的方法上方。方法名称与 bean id 或默认名称相同。该方法的返回类型是向 Spring 应用程序上下文注册的 bean。您可使用 bean 的 setter 方法来设置依赖项,容器将调用它们来连接相关项。
所以正确的配置是这样的。

备注:这里了解下,所有的消息转化类都实现MessageConverter这个接口,它只有两个方法。Jackson2JsonMessageConverter 的继承关系如下:
Jackson2JsonMessageConverter extends AbstractJsonMessageConverter extends AbstractMessageConverter implements MessageConverter。

到这里问题就解决了。第一次写文章,有不对的地方欢迎指正。
网友评论