RabbitMQ竟然无法反序列化List
分析问题原因
首先错误信息是在消费端抛出来的,按理应该是消费端出问题概率较大。但是如果和他说的一样,我生产端发送的消息就是错误的,从而导致消费端出问题呢?这对这个疑问,我先断开消费端,然后发送一条消息,并通过Rabbitmq的管控台来查看消息的内容是否正确。
消息内容如下图所示:
通过上图可以发现,消息体(payload)是一个标准的json串,并且TypeId也是List
,并不是错误信息中的LinkedHashMap
。哈哈哈,到此可以石锤是消费端反序列化的问题了。赶紧把锅甩出去,抽他呀的(自嗨而已),我写的代码怎么可能有bug。
对我爱学习的我,肯定不愿意就这样算了。必须刨根问底,给他上一课。于是我在google一圈发现这竟然是这个bug。有个老哥也发现了,并提交了一个issues: spring-ampq/issues/1279。
大致是说:尝试从 Spring Boot 2.3.1 升级到 2.3.3,然后再升级到 2.3.6。错误信息依然是:List
是LikedHashMap,而不是Foo对象。并通过远程调试确认了这种情况。出于某种原因,他认为没有正确使用泛型类型。恢复到 Spring-AMQP 2.2.7 使它再次工作,并且对象确实是Foo。
然后garyrussell这个人说:他们添加了对抽象类反序列化的支持,如果配置不正确,这会对消息转换器产生一些副作用。然后调查了一下,确认这是一个错误。是由于List是抽象的,新代码认为它不能反序列化。
解决方法是:
converter.setAlwaysConvertToInferredType(true);
后面还提到在 GH-1729: Fix JSON Regression修复这个问题,修复的代码如下:
通过阅读代码发现,修改前的逻辑是: 如果推断类型是抽象的,则返回false也就代表不能转换成推断类型。然后被转换成LinkedHashMap。这也就是出现 LinkedHashMap cannot cast xxxx class
的主要原因。
修改后变成了:如果推断类型是抽象的并且不是容器类型,返回false。也就意味着,虽然推断类型是抽象的,但是如果是容器类型,并且容器内的对象不是抽象的,则可以被转换。这样一来避免了上述问题的产生了。
前面还提到了通过增加配置来解决。解决起来就相对简单粗暴了,始终转换推断类型。
解决办法
到此问题分析完毕,简单总结一下解决方法。主要有两种:
-
在消费端开启如下配置即可:
// 始终转换推断类型
converter.setAlwaysConvertToInferredType(true);
-
升级版本:由于GH-1729: Fix JSON Regression合并到了2.2.13.RELEASE。所以只需要将 spring-amqp 升级到 2.2.13.RELEASE 或以上。或者升级SpringBoot版本到2.3.7.RELEASE。
结尾
如果觉得对你有帮助,可以多多评论,多多点赞哦,也可以到我的主页看看,说不定有你喜欢的文章,也可以随手点个关注哦,谢谢。
我是不一样的科技宅,每天进步一点点,体验不一样的生活。我们下期见!
本文分享自微信公众号 - 不一样的科技宅(byydkjz)。
如有侵权,请联系 support@oschina.cn 删除。
本文参与“OSC源创计划”,欢迎正在阅读的你也加入,一起分享。
{{m.name}}