美文网首页程序员
记一次Rabbitmq配置错误--MessageConversi

记一次Rabbitmq配置错误--MessageConversi

作者: 李天碧 | 来源:发表于2018-10-09 10:50 被阅读0次

标签: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中。

MessageConverter.toMessage()方法实现

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

Jackson2JsonMessageConverter.createMessage()方法

点击进去发现这段代码,

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()方法

Jackson2JsonMessageConverter的fromMessage()方法

找到toJavaType()方法中,

看到这两段代码

//找到MessageProperties的header中的_TypeId_,拿到需要实例化的实体类名称

String typeIdHeader = retrieveHeaderAsString(properties, getClassIdFieldName());

JavaType contentClassType = getClassIdType(retrieveHeader(properties, getContentClassIdFieldName()));

getClassIdType方法

这段代码是不是也很熟悉,在错误日志截图里面。跟我们猜测的一样。如果发送方和接收方都用Jackson2JsonMessageConverter的,那它接收到消息的时候会根据发送方的实体类进行序列化,如果接收方没有这个实体类就会报错。所以到这里解决方案就出来了。

方法1:抽取一个公用的依赖包,发送方和接收方都引入统一的实体类。按照上述的配置不动即可。

方法2:发送方配置不动,修改接收方的配置,我们接收方不采用Jackson2JsonMessageConverter即可。看下我最新的配置

接收方配置修改1

但是这样改之后发现还是不行,为什么呢?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 方法来设置依赖项,容器将调用它们来连接相关项。

所以正确的配置是这样的。

接收方修改配置2

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

Jackson2JsonMessageConverter extends AbstractJsonMessageConverter  extends AbstractMessageConverter  implements MessageConverter。

MessageConverter接口

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

相关文章

网友评论

    本文标题:记一次Rabbitmq配置错误--MessageConversi

    本文链接:https://www.haomeiwen.com/subject/bhmjaftx.html