541、RabbitMQ详细入门教程系列 -【Jackson2JsonMessageConvert】 2022.09.05

一、前言概述

RabbitMQ系列文章讲解使用过程中重要知识点,示例都是采用原生Java客户端完成。实际开发过程中大部分使用者都是与Spring进行集成,通过SpringAMQP运用RabbitMQ。接下来几篇文章将会从用法、源码角度讲解SpringAMQP生产级别应用

二、调用论证

    <!--定义消息转换器-->
    <bean id="jackson2JsonMessageConverter" class="org.springframework.amqp.support.converter.Jackson2JsonMessageConverter"/>

    <!--定义队列监听-->
    <rabbit:listener-container connection-factory="providerConnection" message-converter="jackson2JsonMessageConverter">
        <rabbit:listener id="baseConsumer" queues="baseQueue" ref="commonConsumer" method="consumerListener"/>
    </rabbit:listener-container>
@Component
public class CommonConsumer {
    
    public void consumerListener(byte[] message){
        System.out.println("=======使用字节数组进行处理============");
        System.out.println(new String(message));
    }
    
    public void consumerListener(String message){
        System.out.println("=======使用字符串进行处理============");
        System.out.println(message);
    }
    
    public void consumerListener(Map message){
        System.out.println("=======使用Map集合进行处理============");
        System.out.println(message);
    }
    
    public void consumerListener(List<TestPojo> message){
        System.out.println("=======使用List集合进行处理============");
        System.out.println(message);
    }
    
    public void consumerListener(TestPojo message){
        System.out.println("=======使用实体类集合进行处理============");
        System.out.println(message);
    }
    
}

2.1 默认byte[]处理

SpringAMQP针对RabbitMQ中的消息封装为对象Message,当生产者未做任何处理时消费者将处理为byte[]进行消费

        TestPojo messageBody = new TestPojo("zsl",23);
        Gson gson = new Gson();
        String bodyJson = gson.toJson(messageBody);
        MessageProperties properties = new MessageProperties();
        Message message = new Message(bodyJson.getBytes(),properties);
        rabbitTemplate.convertAndSend("baseFanoutExchange","",message);
        return "success";

2.2 优化为Map

经过研究发现当Message设置MessageProperties对象的contentType属性 为application/json后消费者这会将其处理为Map使用

        TestPojo messageBody = new TestPojo("zsl",23);
        Gson gson = new Gson();
        String bodyJson = gson.toJson(messageBody);
        MessageProperties properties = new MessageProperties();
        
        // 定义ContentType为application/json消息消费处理为map
        properties.setContentType(MessageProperties.CONTENT_TYPE_JSON);
        
        Message message = new Message(bodyJson.getBytes(),properties);
        rabbitTemplate.convertAndSend("baseFanoutExchange","",message);
        return "success";

2.3 优化为List

当消息体为当个对象时处理为Map没有问题,因为JSON数据转换的过程中对象都会被默认的映射为key-value形式的Map。如果消息是一个集合,自然会被处理为List

        TestPojo messageBody1 = new TestPojo("zsl",23);
        TestPojo messageBody2 = new TestPojo("zsl",23);
        TestPojo messageBody3 = new TestPojo("zsl",23);
        List<TestPojo> messageBodys = new ArrayList<>(3);
        messageBodys.add(messageBody1);
        messageBodys.add(messageBody2);
        messageBodys.add(messageBody3);
        Gson gson = new Gson();
        String bodyJson = gson.toJson(messageBodys);
        MessageProperties properties = new MessageProperties();
    
        // 如果传入List消费将处理为List
        properties.setContentType(MessageProperties.CONTENT_TYPE_JSON);
    
        Message message = new Message(bodyJson.getBytes(),properties);
        rabbitTemplate.convertAndSend("baseFanoutExchange","",message);
        return "success";

2.4 优化为对象

经过数组 -> Map/List处理对于开发者而言并没有丝毫意义,并不是理想的终极目标。就想在入参处通过对象处理消息体,网上很多文章包括官网教程都会告诉你有以下两个方法:

生产者直接指定消费者项目中消息对应对象的完全路径:生产者与消费者耦合严重
生产者配置映射关系,消费者根据映射关系转换:推荐,完全解耦

第一种方式就不再赘述,毕竟肯定在生产中是不可能使用上的,第二种方式首先需要更改Jackson2JsonMessageConvert如下配置:

    <!--定义消息转换映射-->
    <bean id="defaultJackson2JavaTypeMapper" class="org.springframework.amqp.support.converter.DefaultJackson2JavaTypeMapper">
        <property name="idClassMapping">
            <map>
                <entry key="TestPojo">
                    <value type="java.lang.Class">com.zsl.rabbitmq.pojo.TestPojo</value>
                </entry>
            </map>
        </property>
    </bean>
    <!--定义消息转换器-->
    <bean id="jackson2JsonMessageConverter" class="org.springframework.amqp.support.converter.Jackson2JsonMessageConverter">
        <property name="javaTypeMapper" ref="defaultJackson2JavaTypeMapper"/>
    </bean>

然后在生产者发送消息时需要指定MessageProperties的Header属性__TypeId__为映射关系的key,如下所示:

        TestPojo messageBody = new TestPojo("zsl",23);
        Gson gson = new Gson();
        String bodyJson = gson.toJson(messageBody);
        MessageProperties properties = new MessageProperties();
    
        properties.setContentType(MessageProperties.CONTENT_TYPE_JSON);
        // 定义__TypeId__映射关系消费处理为对象
        properties.getHeaders().put("__TypeId__","TestPojo");
    
        Message message = new Message(bodyJson.getBytes(),properties);
        rabbitTemplate.convertAndSend("baseFanoutExchange","",message);
        return "success";

三、源码论证

任何技术学习都离不开它的落脚点源码,接下来通过Jackson2JsonMessageConvert源码阅读弄清楚一下三个问题:

默认返回byte[]
ContentType作用
__TypeId__作用

3.1 默认byte[]

看到Jackson2JsonMessageConvert的抽象类AbstractJackson2MessageConverter,其中有个方法叫fromMessage
在这里插入图片描述
当contentType为null时直接取出Message的body返回,自然是byte[]

3.2 ContentType作用

在这里插入图片描述

debug跟一下你会发现第二个判断条件就是在判断是否将其进行JSON处理,所以当contentType属性为设置为application/json时还是会直接返回byte数组

3.3 TypeId 作用

当生产者消息中带有TypeId__继续debug跟进发现会进入源码204行分支,这个分支中就会获取到映射的对象Class实例,然后进行JSON的转换返回
在这里插入图片描述

四、参考链接

[01] RabbitMQ详细入门教程系列 -【Jackson2JsonMessageConvert】

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值