(踩坑篇)rabbitmq不同模块序列化和反序列化

什么是序列化和反序列化

序列化(Serialization)和反序列化(Deserialization)是将对象转换为字节流或将字节流转换为对象的过程。

序列化是指将对象转换为字节流的过程。在序列化时,对象的状态信息(例如属性值、字段值等)被转换为一串字节,以便能够在网络上传输或者保存到磁盘上。序列化可以将对象持久化,并且使其能够在不同的环境中进行传输和恢复。序列化通常用于分布式系统、缓存、消息队列等场景。

反序列化是指将字节流恢复为对象的过程。在反序列化时,字节流被解析并还原为对应的对象,使其可以在内存中重新使用。反序列化是序列化的逆过程,通过反序列化,我们可以重新获得序列化之前的对象实例及其状态信息。

序列化和反序列化的主要目的是实现对象的持久化和跨网络传输。通过序列化和反序列化,我们可以将对象转换为字节流,然后在需要的时候重新恢复成对象,使得对象的状态可以被保存和传输。

rabbitmq中的序列化和反序列化

在 RabbitMQ 中,消息的序列化和反序列化是指将消息体转换为字节流以便发送到 RabbitMQ 服务器,并且在接收消息时将字节流还原为消息体的过程。

通常情况下,当你向 RabbitMQ 发送消息时,消息体需要被序列化成字节流。RabbitMQ 不会直接处理对象,而是处理字节流。因此,在发送消息之前,你需要将消息体序列化为字节流。同样地,当消费者从 RabbitMQ 接收消息时,需要将接收到的字节流反序列化为原始的消息体对象。

在 RabbitMQ 中,最常见的消息序列化方式是将消息体序列化为 JSON 或者其他类似的格式。在生产者端,你可以将对象转换为 JSON 字符串并将其作为消息体发送到 RabbitMQ;在消费者端,你可以从接收到的 JSON 字符串中解析出对象。

实现

RabbitMQ 提供了 Jackson2JsonMessageConverter 来支持消息内容 JSON 序列化与反序列化
消息发送者在发送消息时应设置 MessageConverter 为 Jackson2JsonMessageConverter
rabbitTemplate.setMessageConverter(new Jackson2JsonMessageConverter());

 消费者

package com.example.user.config;

import com.fasterxml.jackson.databind.ObjectMapper;
import lombok.Data;
import org.springframework.amqp.core.*;
import org.springframework.amqp.rabbit.annotation.RabbitListenerConfigurer;
import org.springframework.amqp.rabbit.config.SimpleRabbitListenerContainerFactory;
import org.springframework.amqp.rabbit.connection.ConnectionFactory;
import org.springframework.amqp.rabbit.listener.RabbitListenerContainerFactory;

import org.springframework.amqp.rabbit.listener.RabbitListenerEndpointRegistrar;
import org.springframework.amqp.support.converter.Jackson2JsonMessageConverter;
import org.springframework.amqp.support.converter.MessageConverter;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.messaging.converter.MappingJackson2MessageConverter;
import org.springframework.messaging.handler.annotation.support.DefaultMessageHandlerMethodFactory;

import java.util.HashMap;
import java.util.Map;

/**
 * @ClassName RabbitMQConfig
 * @Author Larry
 * @create 2024/3/8 0008 15:23
 */
@Configuration
@Data
public class RabbitMQConfig   {
    @Bean
    public MessageConverter jsonMessageConverter(ObjectMapper objectMapper) {
        return new Jackson2JsonMessageConverter(objectMapper);
    }
}

生产者

 @Bean
    public RabbitTemplate rabbitTemplate(ConnectionFactory connectionFactory) {
        RabbitTemplate rabbitTemplate = new RabbitTemplate(connectionFactory);
        rabbitTemplate.setMessageConverter(new Jackson2JsonMessageConverter());
        return rabbitTemplate;
    }

然后理论上来说,就可以实现正常的发送接受消息了。

踩坑

然而我在接受消息时确一直报错,只有String的消息才能被消费,而我发送和接受都是用的一个对象,而且mq管理页面可以接受到消息,而消费者不行。于是我觉得是反序列化出了问题,

开始各种查阅资料配置mq的序列化和反序列化,都不管用。

于是我开始仔细阅读报错信息:

Caused by: org.springframework.amqp.rabbit.support.ListenerExecutionFailedException: Listener threw exception
	at org.springframework.amqp.rabbit.listener.AbstractMessageListenerContainer.wrapToListenerExecutionFailedExceptionIfNeeded(AbstractMessageListenerContainer.java:1705) [spring-rabbit-2.2.10.RELEASE.jar:2.2.10.RELEASE]
	at org.springframework.amqp.rabbit.listener.AbstractMessageListenerContainer.doInvokeListener(AbstractMessageListenerContainer.java:1595) [spring-rabbit-2.2.10.RELEASE.jar:2.2.10.RELEASE]
	at org.springframework.amqp.rabbit.listener.AbstractMessageListenerContainer.actualInvokeListener(AbstractMessageListenerContainer.java:1510) [spring-rabbit-2.2.10.RELEASE.jar:2.2.10.RELEASE]
	at org.springframework.amqp.rabbit.listener.AbstractMessageListenerContainer.invokeListener(AbstractMessageListenerContainer.java:1498) [spring-rabbit-2.2.10.RELEASE.jar:2.2.10.RELEASE]
	at org.springframework.amqp.rabbit.listener.AbstractMessageListenerContainer.doExecuteListener(AbstractMessageListenerContainer.java:1489) [spring-rabbit-2.2.10.RELEASE.jar:2.2.10.RELEASE]
	at org.springframework.amqp.rabbit.listener.AbstractMessageListenerContainer.executeListener(AbstractMessageListenerContainer.java:1433) [spring-rabbit-2.2.10.RELEASE.jar:2.2.10.RELEASE]
	... 6 common frames omitted
Caused by: org.springframework.amqp.support.converter.MessageConversionException: failed to resolve class name. Class not found [com.example.vochers.domain.CouponRecordMessage]
	at org.springframework.amqp.support.converter.DefaultJackson2JavaTypeMapper.getClassIdType(DefaultJackson2JavaTypeMapper.java:189) ~[spring-amqp-2.2.10.RELEASE.jar:2.2.10.RELEASE]
	at org.springframework.amqp.support.converter.DefaultJackson2JavaTypeMapper.fromTypeHeader(DefaultJackson2JavaTypeMapper.java:146) ~[spring-amqp-2.2.10.RELEASE.jar:2.2.10.RELEASE]
	at org.springframework.amqp.support.converter.DefaultJackson2JavaTypeMapper.toJavaType(DefaultJackson2JavaTypeMapper.java:122) ~[spring-amqp-2.2.10.RELEASE.jar:2.2.10.RELEASE]
	at org.springframework.amqp.support.converter.AbstractJackson2MessageConverter.doFromMessage(AbstractJackson2MessageConverter.java:309) ~[spring-amqp-2.2.10.RELEASE.jar:2.2.10.RELEASE]
	at org.springframework.amqp.support.converter.AbstractJackson2MessageConverter.fromMessage(AbstractJackson2MessageConverter.java:273) ~[spring-amqp-2.2.10.RELEASE.jar:2.2.10.RELEASE]
	at org.springframework.amqp.support.converter.AbstractJackson2MessageConverter.fromMessage(AbstractJackson2MessageConverter.java:253) ~[spring-amqp-2.2.10.RELEASE.jar:2.2.10.RELEASE]
	at org.springframework.amqp.rabbit.listener.adapter.AbstractAdaptableMessageListener.extractMessage(AbstractAdaptableMessageListener.java:302) ~[spring-rabbit-2.2.10.RELEASE.jar:2.2.10.RELEASE]
	at org.springframework.amqp.rabbit.listener.adapter.MessagingMessageListenerAdapter$MessagingMessageConverterAdapter.extractPayload(MessagingMessageListenerAdapter.java:323) ~[spring-rabbit-2.2.10.RELEASE.jar:2.2.10.RELEASE]
	at org.springframework.amqp.support.converter.MessagingMessageConverter.fromMessage(MessagingMessageConverter.java:130) ~[spring-amqp-2.2.10.RELEASE.jar:2.2.10.RELEASE]
	at org.springframework.amqp.rabbit.listener.adapter.MessagingMessageListenerAdapter.toMessagingMessage(MessagingMessageListenerAdapter.java:205) ~[spring-rabbit-2.2.10.RELEASE.jar:2.2.10.RELEASE]
	at org.springframework.amqp.rabbit.listener.adapter.MessagingMessageListenerAdapter.onMessage(MessagingMessageListenerAdapter.java:132) ~[spring-rabbit-2.2.10.RELEASE.jar:2.2.10.RELEASE]
	at org.springframework.amqp.rabbit.listener.AbstractMessageListenerContainer.doInvokeListener(AbstractMessageListenerContainer.java:1591) [spring-rabbit-2.2.10.RELEASE.jar:2.2.10.RELEASE]
	... 10 common frames omitted
Caused by: java.lang.ClassNotFoundException: com.example.vochers.domain.CouponRecordMessage
	at java.net.URLClassLoader.findClass(URLClassLoader.java:387) ~[na:1.8.0_372]
	at java.lang.ClassLoader.loadClass(ClassLoader.java:418) ~[na:1.8.0_372]
	at sun.misc.Launcher$AppClassLoader.loadClass(Launcher.java:352) ~[na:1.8.0_372]
	at java.lang.ClassLoader.loadClass(ClassLoader.java:351) ~[na:1.8.0_372]
	at java.lang.Class.forName0(Native Method) ~[na:1.8.0_372]
	at java.lang.Class.forName(Class.java:348) ~[na:1.8.0_372]
	at org.springframework.util.ClassUtils.forName(ClassUtils.java:284) ~[spring-core-5.2.8.RELEASE.jar:5.2.8.RELEASE]
	at org.springframework.amqp.support.converter.DefaultJackson2JavaTypeMapper.getClassIdType(DefaultJackson2JavaTypeMapper.java:185) ~[spring-amqp-2.2.10.RELEASE.jar:2.2.10.RELEASE]

这是其中一小部分,也是关键所在。

他一直在报找不到我传入的对象的类,于是我查看了我项目的整体结构,大胆推理,发现了问题所在。因为我这并不是一个完整的项目,因为只是想实现部分demo,就几乎所有东西都在这俩模块,没对公共部分进行抽离

也就是说,我传入的那个类,在两个类都有,属于是两个类,在我接受参数的时候,先对第一个模块的类进行反射,然后对应第二个类,然后发现找不到第一个类,因为它们属于不同模块,路径是不同的。

在 Java 中,当使用反射加载类时,通常是根据类的全限定名(包括包路径)来进行加载的。如果类的全限定名是正确的,Java 的 ClassLoader 应该能够根据类的包路径找到对应的类文件并加载类。所以,当使用反射时,确保提供的类的全限定名是正确的,并且类文件在类路径下可被找到。这样系统的 ClassLoader 才能够成功加载该类。如果类的全限定名不正确,或者类文件不在类路径下,就会导致 ClassNotFoundException 异常。

解决

增加commom,抽离出公共类就完了

再次测试

成功被消费

结语

打好基础,这次bug本质就是对反射和序列化理解不到位,同时要细看报错信息,不要妄自猜测报错原因。

  • 25
    点赞
  • 18
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
在使用RabbitMQ时,序列化是一个重要的概念。序列化是将对象转化为可以在网络传输或存储中使用的字节序列的过程。使用序列化可以方便地将对象在不同系统之间进行传递和交互。 在RabbitMQ中,可以使用不同序列化方式来处理消息的序列化。一种常用的方式是使用Jackson2JsonMessageConverter。这是一个基于Jackson库的消息转换器,可以将对象序列化为JSON格式的字符串进行传输。通过配置RabbitTemplate的bean,将消息转译器设置为Jackson2JsonMessageConverter,可以实现将对象序列化为JSON串。例如,在任意配置类下提供以下代码: @Bean public RabbitTemplate jacksonRabbitTemplate(ConnectionFactory connectionFactory) { RabbitTemplate rabbitTemplate = new RabbitTemplate(connectionFactory); rabbitTemplate.setMessageConverter(new Jackson2JsonMessageConverter()); return rabbitTemplate; } 除了Jackson2JsonMessageConverter,RabbitMQ还提供了其他的消息转换器实现,例如SimpleMessageConverter。这些不同的消息转换器实现了RabbitMQ的MessageConverter接口,可以根据需求选择合适的转换器。 通过选择适当的序列化方式,可以提高RabbitMQ处理大数据量时的性能。使用序列化可以将对象转化为可传输的字节序列,并且在接收端可以将字节序列反序列化为对象,实现消息的传递和消费。<span class="em">1</span><span class="em">2</span><span class="em">3</span> #### 引用[.reference_title] - *1* *3* [RabbitMq消息序列化简述](https://blog.csdn.net/zhaozhenzuo/article/details/46623213)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v92^chatsearchT3_1"}}] [.reference_item style="max-width: 50%"] - *2* [工作随笔——rabbitmq消息的序列化反序列化springboot)](https://blog.csdn.net/qq_43585377/article/details/109203762)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v92^chatsearchT3_1"}}] [.reference_item style="max-width: 50%"] [ .reference_list ]

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值