[RocketMQ]转换器

背景:

在一次业务联调时,客户说无法解析rocketmq中的消息(我们是用的消息协议是google的protobuf),通过rocketmq的控制台发现,消息变成了json串如下:

而客户想要的是如下样子的:

观察两者可以发现,样子是截然不同的,一个变成了json串,一个是乱码的样子。

然后查看我们的代码,发现是在发送消息时,用错了Message对象。下面详细说明问题点:

在springboot中通过rocketmqTemplate发送消息,一般使用如下方式:

rocketMQTemplate.sendOneWay(topic,message);

我们在创建message的时候,一般有两种方式如下,注意观察Message的包:

方式一:对应于第一个json的图片

//方式一
 Demo1.Person person = Demo1.Person.newBuilder().setId(1).setEmail("b.163.com").setName("小里3").build();
org.apache.rocketmq.common.message.Message msg = new org.apache.rocketmq.common.message.Message();
msg.setBody(person.toByteArray());
rocketMQTemplate.sendOneWay(topic,msg);

方式二:对应第二个乱码的样子的图片

//方式二
Demo1.Person person = Demo1.Person.newBuilder().setId(1).setEmail("b.163.com").setName("小里3").build();
byte[] newByteArray =person.toByteArray();
org.springframework.messaging.Message msg = MessageBuilder.withPayload(newByteArray).build();
rocketMQTemplate.sendOneWay("test5",msg);

正如我们看到的,spring和rocketmq都有一个Message对象,这两个都可以放到rocketMqTemplate中使用,但是这二者有个明显的区别在于,rocektmq的Message对象在发送时,会将我们发送的对象进行json的序列化(也就是图一看到的,将序列化成json的字符串放到rocketmq中),而spring的Message对象是将字节数组放到rocketmq中,也就是看到的乱码的样子啦。

为什么放入的都是对象,但是最终放到rocketmq中的结果不同呢?主要是因为在发送消息时,会根据对象的不同,使用了了不同的消息转换器对消息内容进行了序列化。下面通过源码来看一探究竟:

看下图,以RocketmqTemplate的sendOneWay方法为例,你会发现这个方法有两个(红框),也就是方法重载了,当sendOneWay传入的参数是spring的Message时会调用【1】,当传入的参数是其他类型时便会调用【2】,然后在【2】中组建一个spring的Mesage在调用【1】,这一步会影响到后面要讲的消息转换器的选择,因为palyload的内容被二次封装了,记住这里,后面会用到这里

然后在这个createRocketMqMessage()方法,就会将我们的消息通过转换器进行转换,比如把消息变成字节数组还是序列换成json串,然后把转换完成的结果放到roceketmq的Message对象发送出去。如下图:

在这一步的转换过程中,就涉及到了序列化的问题,也就是最开头我们说的是将对象序列化为json还是字节数组的问题了,至于最后到底变成什么样子,取决于它内部转换器MessageConverter(默认一共有四个转换器)。如下图:

上图这个doConvert就是用来做转换的了,里面会选择处合适的(转换器的support方法,默认都是通过类型进行判断)转换器,将我们传入的原始消息进行转化。例如转为json格式,或者维持不变。

在doConvert方法中,会调用一个CompositeMessageConverter的转换器,这是一个代理了,这里面会遍历所有convert,然后找到符合的转换器,如下图:

我们说过,到底用哪个转换器,就是在toMessage这个方法里来确定的,并且转换也是在这个方法中完成的。这个方法也是个重载的方法,如下图,这里很重要,他跟最后用哪个转换器有一定关系。

注意看这个canConvertTo方法,他用来判断消息是否可以被当前的这个消息转换器给进行转换,一般来说都是supports方法来判断,supports里面通过class来判断是否支持。如下图

但是这些消息转换器中的MappingJackson2MessageConverter是直接重写了canConvertTo方法,所以当我们发送的消息对象是Spring的Message时,它里面的payload属性就是字节数组,所以当按照顺先执行ByteArrayMessageConverter时,他的supports方法会判断这个payload是不是数组对象,满足条件就用这个转换器转换了。

但是当我们的消息用的是rocketmq的Message对象时,就会想前面【1】处所写的那样,会先进行一次包装,将rocketmq的Message对象作为payload封装到spring的Message对象中,此值这些转换器的supports方法将都不满足,因为类型都不匹配。只有到MappingJackson2MessageConverter时,因为它重写了canConvertTo方法,所以就不使用supports了。它canConvertTo中返回了true,所以就会将消息转化为了json对象,然后将这个json放到mq中了。

总结:

此篇文章的关键点在于消息转换器,如下:

使用哪个转换器决定了放到mq中的数据的样子,是字节是字符串还是json串等等。

另外,当通过MappingJackson2MessageConverter转化后,可能会发现字节数组在转换前不同了,那是因为是将转换器转换后的数据的字节数组放到了里面,肯定与原始的字节数组中的内容不同了。

扩展:

考虑一下,我们是不是可以自定义自己的转换器

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
RocketMQ监听器是用于监听RocketMQ消息的回调函数。当消费者接收到RocketMQ的消息时,监听器会被触发,并执行相应的逻辑处理。 在RocketMQ中,有两种类型的监听器:MessageListener和MessageListenerConcurrently。 1. MessageListener:该监听器适用于顺序消费模式,即消息的消费必须按照消息发送的顺序进行处理。当消费者接收到消息时,MessageListener会按照顺序逐个处理消息,确保消费的顺序性。 2. MessageListenerConcurrently:该监听器适用于并发消费模式,即消息的消费可以同时进行。当消费者接收到消息时,MessageListenerConcurrently会以多线程的方式并发处理消息,提高消息的处理效率。 为了使用RocketMQ监听器,你需要实现相应的接口并重写其中的方法。例如,对于Java客户端,你可以实现RocketMQ的MessageListener接口或MessageListenerConcurrently接口,并在实现类中实现onMessage方法,该方法会在接收到消息时被触发。 示例代码如下: ```java import org.apache.rocketmq.client.consumer.listener.MessageListenerConcurrently; import org.apache.rocketmq.common.message.MessageExt; import java.util.List; public class MyMessageListener implements MessageListenerConcurrently { @Override public ConsumeConcurrentlyStatus consumeMessage(List<MessageExt> messages, ConsumeConcurrentlyContext context) { for (MessageExt message : messages) { // 处理消息逻辑 System.out.println("Received message: " + new String(message.getBody())); } return ConsumeConcurrentlyStatus.CONSUME_SUCCESS; } } ``` 以上代码是一个简单的RocketMQ消息监听器的示例,当消费者接收到消息时,会打印消息的内容。你可以根据实际需求,在consumeMessage方法中编写自己的业务逻辑。 注意:RocketMQ的监听器需要与消费者进行绑定,具体的绑定方式可以参考RocketMQ官方文档或相关的教程。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值