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[] 類型。
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM