为什么我不推荐你使用RabbitMQ的消息转换功能
改版:
发送消息与订阅消息取消使用amqp提供的消息序列化与反序列化功能,使用String类型,发送消息时手动转化为json字符串再发送,消费消息时手动json反序列化。
背景:
如果使用自动序列化与反序列化功能,即给Rabbitmq配置Jackson2JsonMessageConverter消息转化器,当我们修改消息Body的java类型名称或者包名时,消费历史消息就会抛出ClassNotFoundException异常。
1、不做兼容上线,但需要:
- 确保不会有新的消息进入队列;
- 确保队列中的消息已经消费完。
2、粗暴方式,直接清空队列,丢弃历史消息;
3、做兼容,给旧消息创建一个类名匹配的消息Body类型,添加一个@RabbitHandler方法处理旧消息。
这是因为Rabbitmq为了实现一个队列支持多个方法消费(即@RabbitHandler注解的方法),每个方法消费不同Java类型的消息Body,在消费到消息时,就需要先反序列化出消息Body,才能根据消息Body的类型去匹配一个消费方法消费消息,如DelegatingInvocableHandler#invoke方法源码所示。
- // org.springframework.amqp.rabbit.listener.adapter.DelegatingInvocableHandler#invoke
- public InvocationResult invoke(Message<?> message, Object... providedArgs) throws Exception {
- // 获取消息body类型
- Class<? extends Object> payloadClass = message.getPayload().getClass();
- // 匹配的方法
- InvocableHandlerMethod handler = getHandlerForPayload(payloadClass);
- // 调用方法消费
- Object result = handler.invoke(message, providedArgs);
- //....
- }
由于需要在匹配消息消费方法之前就需要解析出消息Body,也就是要先知道消息Body的Java类型才能实现json反序列化,这就要求消息生产者在发送消息时不得不在消息头添加一个参数表示消息Body的Java类型,如下图所示。
在消息消费阶段,Jackson2JsonMessageConverter也需要先根据消息头的TypeId获取JavaType,再执行反序列化操作,当类名修改时,或者生产者和消费者各自定义的类名不同,都将会导致反序列化失败。
除非确保消息Body的类名不会变,且生产者与消费者定义的完整类名相同,否则不建议使用自动序列化与反序列化功能。
本文转载自微信公众号「Java艺术」,作者wujiuye 。转载本文请联系Java艺术公众号。
相关文章
- Java要抛弃祖宗的基业,Java程序员危险了!
- 十大 Java 语言特性
- JVM 三色标记算法,原来是这么回事!
- 聊聊 Spring 事务控制策略以及 @Transactional 失效问题避坑
- 写给 Java 程序员的前端 Promise 教程
- 写给 Java 程序员的前端 Promise 教程,你学会了吗?
- Java 中为什么不全部使用 Static 方法?
- Java 池化技术你了解多少?
- Java 服务 Docker 容器化优秀实践
- Spring Boot + EasyExcel导入导出,简直太好用了!
- 我们一起聊聊 Java 内存泄漏
- CentOS 下安装 Docker 极简教程
- JDK 19 功能集冻结:Java 19 只有七个新特性
- 关于 CMS 垃圾回收器,你真的懂了吗?
- 为什么会有这么多编程语言?
- 改善Java代码的八个建议
- 接口流量突增,如何做好性能优化?
- Java 以编程方式创建JAR文件
- POJO、Java Bean是如何定义的
- Spring 的 Bean 明明设置了 Scope 为 Prototype,为什么还是只能获取到单例对象?