### 准备

## 目标

了解 Spring AMQP 如何用 POJO 处理消息

## 前置知识

《Spring AMQP 源码分析 04 - MessageListener》

## 相关资源

Sample code:<https://github.com/gordonklg/study>,rabbitmq module
源码版本:Spring AMQP 1.7.3.RELEASE

## 测试代码

gordon.study.rabbitmq.springamqp.AsyncConsumerWithAdapter.java

 

### 分析

## MessageListenerAdapter

MessageListenerAdapter 利用反射机制使普通的 POJO 就能处理消息。
 
MessageListenerAdapter 本身实现了 ChannelAwareMessageListener 接口,整个逻辑的核心就在 onMessage 方法中。
 

 
第269行获取实际处理消息的对象 delegate,本例中即为 CommonPrintBean 实例。
 
接下来判断 delegate 是否为 MessageListener 或 ChannelAwareMessageListener 接口,如果是,则调用 onMessage 方法处理。也就是说,MessageListenerAdapter 的委托实例可以是 MessageListener 或 ChannelAwareMessageListener。
对于本例这种 POJO 委托类,第288行先抽取消息。extractMessage 方法会尝试获取 MessageConverter,MessageListenerAdapter 默认的消息转化器是 SimpleMessageConverter。如果存在 MessageConverter,则调用其 fromMessage 方法将消息转化为对象。否则直接返回 Message 本身。注意,Spring AMQP 默认的 SimpleMessageConverter 很容易坑人,请在脑海中留下印象:消息在被对应的方法消费前,会被 MessageConverter 做一次转换!

 
第289行,根据原始的 message 信息,通过 getListenerMethodName 方法确定该消息应该被哪个方法消费。核心属性是 MessageListenerAdapter 的 Map<String, String> queueOrTagToMethodName,其 key 为队列名或 consumer tag,值为方法名。也就是说,我们可以为不同的队列设置不同的方法,也可以为不同的 Consumer 设置不同的方法。如果没有匹配的方法,则使用默认方法 handleMessage。

 

第297行,根据 convertedMessage 创建参数列表。MessageListenerAdapter 创建的参数列表永远是长度为1的数组,也就是说,POJO 中合理的消息处理方法必然都是只有一个参数的。

 
第298行,利用反射机制调用对应方法消费消息。显然,convertedMessage 的类型决定了反射会调用哪个同名方法。
 

## 示例代码分析

示例代码中 CommonPrintBean 提供了三个不同的 printMessage 方法。考虑到默认使用 SimpleMessageConverter,convertedMessage 类型为 String,所以会调用 String 参数版本的 printMessage 方法。
 
如果打开第22行注释,将 MessageConverter 设置为 null,则会调用 Message 参数版本的 printMessage 方法。
 
一般来说,不会用到 Object 参数版本的 printMessage 方法,但是提供这个方法可以确保在 MessageListenerAdapter 的委托 POJO 中一定能够找到消息处理方法(打个错误日志也好)。
 

## 异常分析

业务异常与直接使用 MessageListener 接口完全一致。代码第45行抛出的 AmqpRejectAndDontRequeueException 异常会引导框架拒绝消息并使之不重新入队。
 
如果期望的消息消费方法不存在,会抛出被 ListenerExecutionFailedException 包装的 NoSuchMethodException,由于 NoSuchMethodException 是 DefaultExceptionStrategy 的 fatal 异常,因此异常会被 AmqpRejectAndDontRequeueException 再次包装。AsyncMessageProcessingConsumer 的 run 方法循环消费消息逻辑中,遇到 AsyncMessageProcessingConsumer 直接静默处理。所以,如果没有对应的方法,框架最终会把所有的消息都转到死信队列中去。
 
 
 
 

Spring AMQP 源码分析 07 - MessageListenerAdapter的更多相关文章

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

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

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

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

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

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

  4. Spring AMQP 源码分析 02 - CachingConnectionFactory

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

  5. Spring AMQP 源码分析 04 - MessageListener

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

  6. Spring AMQP 源码分析 03 - MessageConverter

    ### 准备 ## 目标 了解 Spring AMQP 消息转化实现   ## 相关资源 Quick Tour for the impatient:<http://docs.spring.io/ ...

  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. .Net Core2.0基于DbContext,IActionFilter过滤器实现全局UOW,不使用TransactionScope

    抛弃TransactionScope 之前实现过类似功能是使用的TransactionScope,总碰到这样那样的问题,新项目迁移到.net core2.0下,果断抛弃之前的写法,因为DbContex ...

  2. VS2010/MFC编程入门之三十一(常用控件:树形控件Tree Control 下)

    前面一节讲了树形控件Tree Control的简介.通知消息以及相关数据结构,本节继续讲下半部分,包括树形控件的创建.CTreeCtrl类的主要成员函数和应用实例. 树形控件的创建 MFC为树形控件提 ...

  3. Object-C-Foundation-NSNuber

    NSNumber 是一个数值类型封装起来的数值. 装箱:基础类型->对象类型 NSNumber *number=[NSNumber numberWithInt:12]; 拆箱:对象类型-> ...

  4. Object-C-Foundation-数组排序

    系统类型排序; NSArray *goodsNames =@[@"computer",@"iphone",@"ipad"]; NSArray ...

  5. SSRS创建复合型图表

    SSRS创建复合型图表 1.添加报表数据对应代码: if object_id('tb') is not null drop table tb; go CREATE TABLE tb(yearid in ...

  6. 如何用有NFC功能的手机微信给公交卡充值?入口在那里?

    如何用有NFC功能的手机微信给公交卡充值?入口在那里? 需要两个前提: 1.NFC功能手机授权同意微信获取权限. 2.打开微信,并把公交卡放在手机背面贴紧. 选择下方的[充值金额],可以是10元.20 ...

  7. 中国程序化购买广告解析:RTB/DSP/Ad Exchange/SSP/DMP,思维导图

    中国程序化购买广告解析:RTB/DSP/Ad Exchange/SSP/DMP 概念 程序化购买( Programmatic Buying):通过数字化.自动化.系统化的方式改造广告主.代理公司.媒体 ...

  8. [转载] My97DatePicker日历实现开始日期小于结束日期验证

    <tr align='center'> <td align="right">开始日期: </td> <td align="lef ...

  9. python学习读取配置文件

    配置文件作为一种可读性很好的格式,非常适用于存储程序中的配置数据. 在每个配置文件中,配置数据会被分组(比如“config”和 “cmd”). 每个分组在其中指定对应的各个变量值.如下: # 定义co ...

  10. python-随机数的产生random模块

    random模块用来产生随机数: 查看random模块的方法: import random random.__dir__ Out[39]: <function __dir__> rando ...