Spring AMQP 源码分析 03 - MessageConverter

### 准备

## 目标

了解 Spring AMQP 消息转化实现
 

## 相关资源

 
Sample code:<https://github.com/gordonklg/study>,rabbitmq module
 

## 测试代码

gordon.study.rabbitmq.springamqp.JsonMessage.java

 

### 分析

## MessageConverter

org.springframework.amqp.support.converter.MessageConverter 接口负责消息转化,有两个方法:toMessage 方法将 Java 对象转化为 org.springframework.amqp.core.MessagefromMessage 方法将消息转化为 Java 对象。

Message 类是 Spring AMQP 对消息的封装,其 byte[] body 属性代表消息内容,MessageProperties messageProperties 属性代表消息属性。
 
RabbitTemplate 类持有 MessageConverter 的引用,用来帮助 RabbitTemplate 处理 Message 与 Java 对象之间的转化。
 

## Jackson2JsonMessageConverter

org.springframework.amqp.support.converter.Jackson2JsonMessageConverter 通过 Jackson 2.x 版本进行 Java 对象(POJOs)与 JSON 格式内容之间的转化。
 
toMessage 方法实现逻辑:
  1. 通过 ObjectMapper 将 Java 对象转化为 JSON 字符串,再将字符串转为 byte[]
  2. 设置 MessageProperties,contentType 设为 application/json,contentEncoding 设为 UTF-8,contentLength 设为 byte[] 长度
  3. 向 MessageProperties 的 headers 属性中添加 __TypeId__,其值为 Java 对象的类全名
 
调试中截取的 Message 实际值为: 
(Body:'{"name":"Gordon","birthday":1498024107659,"tall":172}' MessageProperties [headers={__TypeId__=gordon.study.rabbitmq.springamqp.Student}, timestamp=null, messageId=null, userId=null, receivedUserId=null, appId=null, clusterId=null, type=null, correlationId=null, correlationIdString=null, replyTo=null, contentType=application/json, contentEncoding=UTF-8, contentLength=53, deliveryMode=PERSISTENT, receivedDeliveryMode=null, expiration=null, priority=0, redelivered=null, receivedExchange=null, receivedRoutingKey=null, receivedDelay=null, deliveryTag=0, messageCount=null, consumerTag=null, consumerQueue=null])
其中 deliveryMode 默认值为 PERSISTENT(即默认持久化),这是 MessageProperties 定义的默认值
 
fromMessage 方法实现逻辑:
  1. 如果入参 Message 对象的 MessageProperties 属性为 null,或者消息属性 contentType 值既不为空又不包含 json 关键字,则直接返回 Message 的 body (byte[])
  2. 从 MessageProperties 的 headers 属性中读出 __TypeId__ 的值,通过 Jackson 的 API 将之转化为 JavaType 对象,再将 message body 转化为 Java 对象
 
调试中截取的 Message 实际值为: 
(Body:'{"name":"Gordon","birthday":1498032689741,"tall":172}' MessageProperties [headers={__TypeId__=gordon.study.rabbitmq.springamqp.Student}, timestamp=null, messageId=null, userId=null, receivedUserId=null, appId=null, clusterId=null, type=null, correlationId=null, correlationIdString=null, replyTo=null, contentType=application/json, contentEncoding=UTF-8, contentLength=0, deliveryMode=null, receivedDeliveryMode=PERSISTENT, expiration=null, priority=0, redelivered=false, receivedExchange=, receivedRoutingKey=spring, receivedDelay=null, deliveryTag=1, messageCount=0, consumerTag=null, consumerQueue=null])
 

## MessagePropertiesConverter

我们发现前面调试中截取的 Message 实际值在 send 与 receive 方法中并不完全相同。这是因为 RabbitMQ 中定义的 BasicProperties 只是 Spring AMQP 中定义的 MessageProperties 的一个子集,例如 contentLength 并不是 BasicProperties 的属性,所以 receive 方法读取出来的消息默认是不会有 contentLength 值得(因为存不到 RabbitMQ 里面)。
 
org.springframework.amqp.rabbit.support.MessagePropertiesConverter 接口就是用来提供 Spring AMQP MessageProperties 与 RabbitMQ BasicProperties 之间的转化策略的。
 
Spring AMQP 中提供了 org.springframework.amqp.rabbit.support.DefaultMessagePropertiesConverter 实现 MessagePropertiesConverter 接口。细节可以查看以下方法的实现:
 

## SimpleMessageConverter

RabbitTemplate 默认使用 org.springframework.amqp.support.converter.SimpleMessageConverter 作为自己的消息转化器。SimpleMessageConverter 支持字符串、序列化对象和字节数组三种类型。
 
SimpleMessageConverter 的 toMessage 方法根据传入 Java 对象的类型设置 contentType 并将对象转化为 byte[],支持以下 Java 类型:
  • byte[]:contentType 设置为 application/octet-stream
  • String:contentType 设置为 text/plain
  • Serializable:contentType 设置为 application/x-java-serialized-object,body 为对象序列化得到的 byte[]
  • other:contentType 为 MessageProperties 默认值 application/octet-stream,body 为 null。RabbitMQ 可以发送 body 为 null 的消息
 
而 fromMessage 方法也会根据消息的 contentType 决定如何解析消息体,确定方法最终返回的对象类型。如果 contentType 以 text 开头的,则将 body 转化为字符串;如果 contentType 为 application/x-java-serialized-object,则将 body 反序列化为对象;其它情况直接返回 byte[] 形式的 body。
 
由于通过 Jackson2JsonMessageConverter 发布的消息的 contentType 为 application/json,所以通过 SimpleMessageConverter 获取到的消息的消息体是 byte[] 类型。
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
posted @ 2017-06-22 18:38  首夜盲毒预言家  阅读(3640)  评论(0编辑  收藏  举报