RabbitMQ 学习笔记 -- 08 RabbitTemplate 及消息序列化

生产者发送消息时可以为消息指定一些参数

  1. Delivery mode: 是否持久化,1 - Non-persistent,2 - Persistent

  2. Headers:头文件可以有任何名称。这里只能设置长字符串头。

  3. Properties: 设置消息属性(传递模式和头信息是最常见的情况)。无效的属性将被忽略. Valid properties are:

content_type : 消息内容的类型
content_encoding: 消息内容的编码格式
priority: 消息的优先级
correlation_id:关联id
reply_to: 用于指定回复的队列的名称
expiration: 消息的失效时间
message _id: 消息id
timestamp:消息的时间戳
type: 类型
user_id: 用户id
app_id: 应用程序id
cluster_id: 集群id

  1. Payload: 消息内容

在 web 控制台发布消息配置:

web 控制台

web 控制台

RabbitTemplate

RabbitTemplate 中,发现不管是初始化还是默认的 MessageConverter 都是 SimpleMessageConverter

// messageConverter 默认实例化 SimpleMessageConverter
private MessageConverter messageConverter = new SimpleMessageConverter();
...
/**
*  便捷的构造器与setter注入一起使用
*/
public RabbitTemplate() {
    initDefaultStrategies();
}
...
/**
*  设置默认策略。如果需要,子类可以重写。
*/
protected void initDefaultStrategies() {
    setMessageConverter(new SimpleMessageConverter());
}

我们进入SimpleMessageConverter类中看其默认的转换逻辑

/**
 * Converts from a AMQP Message to an Object.
 */
@Override
public Object fromMessage(Message message) throws MessageConversionException {
    Object content = null;
    MessageProperties properties = message.getMessageProperties();
    if (properties != null) {
        String contentType = properties.getContentType();
        // 如果 content_type 是以 text 为开头,则把消息转换成 String 类型
        if (contentType != null && contentType.startsWith("text")) {
            String encoding = properties.getContentEncoding();
            if (encoding == null) {
                encoding = this.defaultCharset;
            }
            try {
                content = new String(message.getBody(), encoding);
            }
            catch (UnsupportedEncodingException e) {
                throw new MessageConversionException("failed to convert text-based Message content", e);
            }
        }
        // 其他类型转换为 application/x-java-serialized-object
        else if (contentType != null && contentType.equals(MessageProperties.CONTENT_TYPE_SERIALIZED_OBJECT)) {
            try {
                content = SerializationUtils.deserialize(
                        createObjectInputStream(new ByteArrayInputStream(message.getBody()), this.codebaseUrl));
            }
            catch (IOException | IllegalArgumentException | IllegalStateException e) {
                throw new MessageConversionException("failed to convert serialized Message content", e);
            }
        }
    }
    if (content == null) {
        content = message.getBody();
    }
    return content;
}

MessageConverter:

消息转换器 MessageConverter 重要的两个方法
// 将java对象和属性对象转换成 Message 对象。
Message toMessage(Object object, MessageProperties messageProperties);

// 将消息对象转换成 java 对象。
Object fromMessage(Message message) throws MessageConversionException;

RabbitTemplate 内部通过 MessageConverterMessage 转换成 java 对象,用于将对象参数解析为convertAndSend方法以及 receiveAndConvert 方法的对象结果。

默认转换器是 SimpleMessageConverter,它能够根据消息内容类型头处理字节数组、字符串和可序列化对象。

SimpleMessageConverter 处理的逻辑

  • 如果 content_type 是以 text 为开头,则把消息转换成 String 类型
  • 如果 content_type的 值是 application/x-java-serialized-object 则把消息序列化为 java 对象,否则,把消息转换成字节数组。

Message 内容对象序列化与反序列化

使用 Java 序列化与反序列化

  • 默认的 SimpleMessageConverter 在发送消息时会将对象序列化成字节数组,若要反序列化对象,需要自定义 MessageConverter
  • SimpleMessageConverter 对于要发送的消息体 body 为 byte[] 时不进行处理,如果是 String 则转成字节数组,如果是 Java 对象,则使用 jdk 序列化将消息转成字节数组,转出来的结果较大,含class类名,类相应方法等信息。因此性能较差。当使用 RabbitMQ 作为中间件时,数据量比较大,此时就要考虑使用类似 Jackson2JsonMessageConverter 等序列化形式以此提高性能

使用 JSON 序列化与反序列化

  • RabbitMQ 提供了 Jackson2JsonMessageConverter 来支持消息内容 JSON 序列化与反序列化
  • 消息发送者在发送消息时应设置 MessageConverterJackson2JsonMessageConverter
@Test
public void demo_06_Producer() {
    String routingKey = "hello";
    TestA a = new TestA();
    a.setFieldA("FBI WARNING");
    // 设置 MessageConverter 
    rabbitTemplate.setMessageConverter(new Jackson2JsonMessageConverter());
    rabbitTemplate.convertAndSend(routingKey, a);
    System.out.println("发送成功");
}
  • 消费者也应该配置 MessageConverterJackson2JsonMessageConverter,这样消费者反序列化就能匹配成功
@Configuration
public class RabbitMQConfig {
    @Bean
    public RabbitListenerContainerFactory<?> rabbitListenerContainerFactory(ConnectionFactory connectionFactory){
        SimpleRabbitListenerContainerFactory factory = new SimpleRabbitListenerContainerFactory();
        factory.setConnectionFactory(connectionFactory);
        // 临时设置 MessageConverter 为 Jackson2JsonMessageConverter
        factory.setMessageConverter(new Jackson2JsonMessageConverter());
        return factory;
    }
}
  • 注意:被序列化对象应提供一个无参的构造函数,否则会抛出异常
  • 1
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值