### 准备

## 目标

了解 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.Message;fromMessage 方法将消息转化为 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[] 类型。
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Spring AMQP 源码分析 03 - MessageConverter的更多相关文章

  1. Spring AMQP 源码分析 07 - MessageListenerAdapter

    ### 准备 ## 目标 了解 Spring AMQP 如何用 POJO 处理消息 ## 前置知识 <Spring AMQP 源码分析 04 - MessageListener> ## 相 ...

  2. Spring AMQP 源码分析 08 - XML 配置

    ### 准备 ## 目标 通过 XML 配置文件使用 Spring AMQP ## 前置知识 <Spring AMQP 源码分析 07 - MessageListenerAdapter> ...

  3. Spring AMQP 源码分析 06 - 手动消息确认

    ### 准备 ## 目标 了解 Spring AMQP 如何手动确认消息已成功消费 ## 前置知识 <Spring AMQP 源码分析 04 - MessageListener> ## 相 ...

  4. Spring AMQP 源码分析 05 - 异常处理

    ### 准备 ## 目标 了解 Spring AMQP Message Listener 如何处理异常 ## 前置知识 <Spring AMQP 源码分析 04 - MessageListene ...

  5. Spring AMQP 源码分析 02 - CachingConnectionFactory

    ### 准备 ## 目标 了解 CachingConnectionFactory 在默认缓存模式下的工作原理   ## 前置知识   <Spring AMQP 源码分析 01 - Impatie ...

  6. Spring AMQP 源码分析 04 - MessageListener

    ### 准备 ## 目标 了解 Spring AMQP 如何实现异步消息投递(推模式) ## 前置知识 <RabbitMQ入门_05_多线程消费同一队列> ## 相关资源 Quick To ...

  7. Spring AMQP 源码分析 01 - Impatient

    ### 准备   ## 目标 了解 Spring AMQP 核心代码   ## 前置知识 RabbitMQ 入门   ## 相关资源   Quick Tour for the impatient:&l ...

  8. Spring Security 源码分析(四):Spring Social实现微信社交登录

    社交登录又称作社会化登录(Social Login),是指网站的用户可以使用腾讯QQ.人人网.开心网.新浪微博.搜狐微博.腾讯微博.淘宝.豆瓣.MSN.Google等社会化媒体账号登录该网站. 前言 ...

  9. spring事务源码分析结合mybatis源码(一)

    最近想提升,苦逼程序猿,想了想还是拿最熟悉,之前也一直想看但没看的spring源码来看吧,正好最近在弄事务这部分的东西,就看了下,同时写下随笔记录下,以备后查. spring tx源码分析 这里只分析 ...

随机推荐

  1. background 背景图片 在IE8中不显示解决方法

    我给ul加了一个背景图片 background 火狐 ie9 ch都显示.唯独在IE8中不显示 之前的样式代码 background: url( rgba(, , , ); 在ie8中改成 backg ...

  2. window.open和window.showModalDialog

    window.open window.open是打开一个新窗口 在window.open打开的窗口中刷新父页面 opener.location.reload(); 打开一个窗口格式:属性可以任意设置 ...

  3. 让声音更清晰,用PR去掉视频中的噪音

    Premiere V7.0没有支持当前文件类型的输入源的问题 25 我是新手,把DVD影片放到电脑里,显示的是VOB文件,导入类型显示的是所有支持格式,于是我就点击了VOB文件,但是说没有支持当前文件 ...

  4. Summary: Class Variable vs. Instance Variable && Class Method

    这里列举的是一些我平时碰到的一些Java Grammar,日积月累. Class Variable vs Instance Variable: Instance variables Instance ...

  5. linux phpize

    phpize是什么 1.phpize是用来扩展php扩展模块的,通过phpize可以建立php的外挂模块. 当php编译完后,在bin下面会有phpize这个脚本文件, 在编译你要添加的扩展模块之前, ...

  6. Perl的变量及语境(一)

    Perl语言中的大部分语句表达式后都紧接一个分号,分隔不同的Perl语句. perl解释器能一次完成编译和运行这两个动作. perl通过一对反引号"``"来表示运行外部命令. 也可 ...

  7. cocos2dx-环境搭建和创建项目(mac用)

    学习一门语言最快的方法就是制作一个简单的项目. 而要制作一个项目必须先搭好环境,即使花上2小时去熟悉环境创建也不算浪费.由于之后的项目会用到cocos2d-x 3.0,这里以3.0为例子(不同的版本写 ...

  8. Python tricks(3) -- list和dict的遍历和方法

    每个人在使用python的过程中都会遍历list和dict. List遍历 最常用最简单的遍历list的方法 a = ["a", "b", "c&qu ...

  9. Linux服务器---mysql忘记root密码

    忘记root密码 如果不小心忘记了root密码,那么mysql就不能再登录了,这时就要重置root密码才行.通过下面的步骤,我们可以重新设置root密码. 1.退出mysql [root@localh ...

  10. 微信公众号为什么要加粉?流量,广告,KPI,吸粉,增粉

    微信公众号为什么要加粉?流量,广告,KPI,吸粉,增粉 1.曾有人这样比喻:当你的粉丝超过100人时,你就像是一本内刊:超过1000人,你就像个布告栏:超过1万人,你就好比一本杂志:超过10万人,你就 ...