优雅的解决SpringBoot集成RabbitMQ序列化和反序列化的思路1

首先说一句我打脸了,Spring-AMQP 1.6之后就支持参数类型推断了,不需要这样麻烦,只要升级就行了。这套逻辑是我为了Spring-AMQP 1.3.9写的,但是最近写文章的时候,是看的Spring-AMQP-1.7.4的源码(新旧项目兼容,我是为了旧项目写的功能,但是写文章到时候看的是新的项目,尴尬)。我写的时候还在想为什么代码不跟印象里不一样了, 由于实在太晚了,就大概看看,没有仔细研究。今天2020-06-14,在研究写方案三的时候,经过仔细研读源码,发现了疏漏,就赶紧改一下,省的误导大家。
如果大家无法升级Spring-AMQP,还得用老版本,这个文章对大家还是有帮助的。

最近又充满的冲劲,打算再把博客捡起来,(っ•̀ω•́)っ✎⁾⁾ 我爱学习

原由

Spring-AMQP 支持 生产者 使用自定义的 Bean,然后通过 MessageConverter 转换成Message 进行发送。消费者 也可以通过 MessageConverterMessage再转化成自定义类。毕竟 Message 构建解析还是挺麻烦的。

MessageConverter有多个子类:

  • 通过 Java SerializableString,纯byte[] 进行传递 :SerializerMessageConverterSimpleMessageConverter
  • 通过 Xml 进行传递:MarshallingMessageConverter
  • 通过 Json 进行传递:JsonMessageConverterJackson2JsonMessageConverter
  • 包装其他的MessageConverter,根据 contentType 进行转发:ContentTypeDelegatingMessageConverter

其中Jackson2JsonMessageConverter 比较常用,使用 Jackson 2 进行转换(以下简称 JsonMessageConverter)。但是 MessageConverter 这个接口有个小问题,它为了封装最通用的转换逻辑,其中 fromMessage 只有一个参数,这导致无法获取 自定义 BeanClass消费者 就无法通过反射构建 Bean

// 将自定义对象转成Message, 生产者
Message toMessage(Object object, MessageProperties messageProperties)
// 将Message转成自定义对象, 消费者
Object fromMessage(Message message)

所以JsonMessageConverter通过实现 AMQP 协议,填充 headers__TypeId__ 的值,来传递 Class的Name。 它 的默认是 填充包括的包名的全称,说的直白点,那就是在不对它进行任何改造的前提下,发送消息的 Bean 和接受消息的 Bean 必须是一样的,不仅是要里面的字段一样,类名一样,连包名都要一样。

所以当 生产者 使用 JsonMessageConverter发送消息时,消费者 可以有如下几种方式来接收:

  • 消费者生产者 依赖相同的 jar
  • 不依赖jar,那就在自己系统建一个相同的 Class ,包名,类名都得相同。
  • 获取 Message,然后自己解析。

其中方案1,方案2 系统之间耦合性太强了,方案3 是个还可以方案,但是我被 SpringMVC 给惯坏了,感觉还是有点麻烦,就想自动转换成 Bean , 然后直接使用就行了。那我就开始研究源码,找到解决方案。

思路

上面已经说了,JsonMessageConverter 是通过填充 __TypeId__ 来实现 json 序列化和反序列化的,那我就找到对应的代码, 修改 __TypeId__ 就行了。虽然说得简单,但是我也是一步步分析源码找到的,接下来讲解我是如何一步步找到对应源码的。

消费者源码分析

首先我根据经验推断,从Message转成 Bean 的时候,必须知道对应 BeanClass ,不然不可能实现转换。然后找到了这段代码,特别好理解, targetJavaTypetargetClass 明确的“暗示”它的作用,毕竟我也是手动创建 并使用过 ObjectMapper 的人(✪ω✪)。
那咱们打开 函数 convertBytesToObject 来验证猜测,看到了熟悉的代码,证明我们的猜测,jsonObjectMapper 就是 Jackson 2 ObjectMapper 的实例。
看到这块我特别的开心,这说明JsonMessageConverter没有什么神秘的,跟 咱们平时 通过 Class来解析 Json 没有什么区别,咱们接下去的目标,就是找到 Class 是如何获取的。

	@Override
	public Object fromMessage(Message message)
			throws MessageConversionException {
   
		// ……省略无关代码……
					if (getClassMapper() == null) {
   
						JavaType targetJavaType = getJavaTypeMapper()
								.toJavaType(message.getMessageProperties());
						content = convertBytesToObject(message.getBody(),
								encoding, targetJavaType);
					}
					else {
   
						Class<?> targetClass = getClassMapper().toClass(
								message.getMessageProperties());
						content = convertBytesToObject(message.getBody(),
								encoding, targetClass);
					}
		// ……省略无关代码……
	}

	private Object convertBytesToObject(byte[] body, String encoding, JavaType targetJavaType) throws IOException {
   
		String contentAsString = new String(body, encoding);
		return this.jsonObjectMapper.readValue(contentAsString, targetJavaType);
	}

	private Object convertBytesToObject(byte[] body, String encoding, Class<?> targetClass) throws IOException {
   
		String contentAsString 
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值