转自首夜盲毒预言家的文章

Spring AMQP 源码分析 01 - Impatient

### 准备

## 目标

了解 Spring AMQP 核心代码

## 前置知识

RabbitMQ 入门

## 相关资源

Quick Tour for the impatient:<http://docs.spring.io/spring-amqp/docs/1.7.3.RELEASE/reference/html/_introduction.html#quick-tour>

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

## 测试代码

gordon.study.rabbitmq.springamqp.Impatient.java

### 分析

## ConnectionFactory分析

org.springframework.amqp.rabbit.connection.ConnectionFactory 是 Spring AMQP 定义的连接工厂接口,负责创建连接。注意 RabbitMQ client 也有一个同名的连接工厂,这儿用的是 Spring AMQP 定义的。


org.springframework.amqp.rabbit.connection.CachingConnectionFactory 是 ConnectionFactory 的一个实现类。它的属性 com.rabbitmq.client.ConnectionFactory rabbitConnectionFactory 引用了一个真正的 RabbitMQ 连接工厂,一般会在构造函数中被创建出来。后面所有的实际连接都是通过这个 rabbitConnectionFactory 创建的,CachingConnectionFactory 只是管理这些连接。

不同于官网示例代码,第16行定义了 URI,表明通过 guest 用户访问 localhost:5672 的 RabbitMQ 服务。原因是我在本机运行时通过 Spring AMQP 自动解析出来的 host 是机器名而不是 localhost,导致 guest 用户没有权限连接,会抛出异常,因此我需要主动将 host 的值设置为 localhost。除了示例代码中用到的通过 URI 指定的方法外,还有以下几种方法:

1. 通过可以指定 hostname 的构造函数。适用面窄,不能设置用户名等其它连接工厂属性

ConnectionFactory connectionFactory = new CachingConnectionFactory("localhost");

2. 自己创建 com.rabbitmq.client.ConnectionFactory

com.rabbitmq.client.ConnectionFactory rabbitConnFactory = new com.rabbitmq.client.ConnectionFactory();

rabbitConnFactory.setHost("localhost");

rabbitConnFactory.setAutomaticRecoveryEnabled(false);

ConnectionFactory connectionFactory = new CachingConnectionFactory(rabbitConnFactory);

3. 通过 AbstractConnectionFactory 获取到内部 rabbitConnectionFactory

AbstractConnectionFactory connectionFactory = new CachingConnectionFactory();

connectionFactory.getRabbitConnectionFactory().setHost("localhost");

4. 通过 AbstractConnectionFactory 封装的方法间接操作 rabbitConnectionFactory

AbstractConnectionFactory connectionFactory = new CachingConnectionFactory();

connectionFactory.setHost("localhost");

## AmqpAdmin分析

org.springframework.amqp.core.AmqpAdmin 接口定义了 AMQP 基础管理操作,主要是对各种资源(交换机、队列、绑定)的申明和删除操作。

org.springframework.amqp.rabbit.core.RabbitAdmin 实现了 AmqpAdmin 接口。通过构造函数传入前面创建的 ConnectionFactory 实例,设置到 RabbitAdmin 的 ConnectionFactory connectionFactory 属性中,同时还在构造函数中创建了一个 RabbitTemplate 实例,设置到 RabbitTemplate rabbitTemplate 属性中。

declareQueue 方法用来申明队列。org.springframework.amqp.core.Queue 是 Spring AMQP 对队列的封装,其属性与 RabbitMQ Java client 中定义的 Queue 的属性基本一致,new Queue("spring"); 相当于 RabbitMQ Java client 中 channel.queueDeclare("spring", true, false, false, null); 指定的队列特性,即队列是持久化、非排他性、非自动删除的。

declareQueue 调用 rabbitTemplate 的 execute(ChannelCallback) 方法,在 ChannelCallback 的回调方法 doInRabbit(com.rabbitmq.client.Channel) 中通过入參 channel 调用 RabbitMQ Java client 提供的 channel.queueDeclare 方法申明队列。代码中有个细节:所有 "amq." 开头的队列会被 Spring AMQP 框架忽略,不会触发 channel.queueDeclare 方法调用。RabbitTemplate 细节下文分析。

## AmqpTemplate分析

org.springframework.amqp.core.AmqpTemplate 接口定义了 AMQP 基础操作,主要为同步的消息收发方法。

org.springframework.amqp.rabbit.core.RabbitTemplate 实现了 AmqpTemplate 接口。类似于 RabbitAdmin,RabbitTemplate 也需要引用外部的 ConnectionFactory 用于创建连接。

顾名思义,RabbitTemplate 就是 RabbitMQ 收发消息的模板方法,类似于 JdbcTemplate 的设计。所以,RabbitTemplate 要实现创建连接、获取信道、收发消息(等实际操作)、消息格式转换、关闭信道与连接等模板代码。

例如,对于 convertAndSend(String routingKey, Object message)方法,首先通过 convertMessageIfNecessary 方法将 Object message 转化为 org.springframework.amqp.core.Message 实例。Message 类是 Spring AMQP 对消息的封装。convertMessageIfNecessary 方法通过获取在 RabbitTemplate 构造函数中创建的 org.springframework.amqp.support.converter.SimpleMessageConverter,调用其 toMessage 方法完成 Message 实例的创建(即消息转化)。

接下来,借助 execute(ChannelCallback action, ConnectionFactory connectionFactory) 方法,在 ChannelCallback 接口的匿名实现类的 doInRabbit(Channel) 方法中实现发送消息功能,代码截图如下:

execute(ChannelCallback action, ConnectionFactory connection) 方法与 ChannelCallback 接口合作,成功地将消息发送(等实际操作)与获取连接和信道这两部分代码隔离开。execute 方法中通过传入的 ConnectionFactory 获取连接和信道,ChannelCallback 接口的 doInRabbit(Channel channel) 方法作为回调函数,通过 channel 参数接受 execute 方法中获取的信道,完成消息发送的具体业务。代码实现很简单,在 execute 方法获取到信道 channel 后,调用 action.doInRabbit(channel); 即可。

调用栈信息:

doSend 方法实现消息发送这个具体操作。本质是通过调用 RabbitMQ Java client 提供的 channel.basicPublish 方法发送消息。

业务操作完成后,execute 方法会回收连接和信道资源,整个消息发送模板功能完成。

receiveAndConvert 方法实现思路与 convertAndSend 基本一致,调用栈如下:

【转】Spring AMQP 源码分析 01 - Impatient相关推荐

  1. Spring AMQP 源码分析 01 - Impatient

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

  2. Spring Cloud源码分析(二)Ribbon(续)

    因文章长度限制,故分为两篇.上一篇:<Spring Cloud源码分析(二)Ribbon> 负载均衡策略 通过上一篇对Ribbon的源码解读,我们已经对Ribbon实现的负载均衡器以及其中 ...

  3. Spring AOP 源码分析 - 拦截器链的执行过程

    1.简介 本篇文章是 AOP 源码分析系列文章的最后一篇文章,在前面的两篇文章中,我分别介绍了 Spring AOP 是如何为目标 bean 筛选合适的通知器,以及如何创建代理对象的过程.现在我们的得 ...

  4. Spring AOP 源码分析 - 创建代理对象

    1.简介 在上一篇文章中,我分析了 Spring 是如何为目标 bean 筛选合适的通知器的.现在通知器选好了,接下来就要通过代理的方式将通知器(Advisor)所持有的通知(Advice)织入到 b ...

  5. Spring AOP 源码分析 - 筛选合适的通知器

    1.简介 从本篇文章开始,我将会对 Spring AOP 部分的源码进行分析.本文是 Spring AOP 源码分析系列文章的第二篇,本文主要分析 Spring AOP 是如何为目标 bean 筛选出 ...

  6. spring AOP源码分析(一)

    spring AOP源码分析(一) 对于springAOP的源码分析,我打算分三部分来讲解:1.配置文件的解析,解析为BeanDefination和其他信息然后注册到BeanFactory中:2.为目 ...

  7. 一步一步手绘Spring AOP运行时序图(Spring AOP 源码分析)

    相关内容: 架构师系列内容:架构师学习笔记(持续更新) 一步一步手绘Spring IOC运行时序图一(Spring 核心容器 IOC初始化过程) 一步一步手绘Spring IOC运行时序图二(基于XM ...

  8. 精尽Spring Boot源码分析 - 内嵌Tomcat容器的实现

    概述 我们知道 Spring Boot 能够创建独立的 Spring 应用,内部嵌入 Tomcat 容器(Jetty.Undertow),让我们的 jar 无需放入 Servlet 容器就能直接运行. ...

  9. 【Spring】Spring AOP源码分析-导读(一)

    文章目录 1.简介 2.AOP 原理 3.AOP 术语及相应的实现 3.1 连接点 - Joinpoint 3.2 切点 - Pointcut 3.3 通知 - Advice 3.4 切面 - Asp ...

最新文章

  1. java 抽象方法 虚方法的区别_声明抽象类(纯虚方法)会大幅增加二进制大小
  2. 深度学习进入芯片领域,揭秘寒武纪神经网络处理器
  3. 神策数据成为 Adjust 在中国首家数据分析合作伙伴
  4. 边缘和智能,是谁在借谁上位?
  5. jQuery_事件学习
  6. 腾讯成功入选LoRa联盟新一届董事会
  7. mac idea配置配置自动清除类中无用的import包
  8. 检查列表中的所有元素在Python中是否相同
  9. CentOS 7.x下部署和配置zabbix 3.2.x监控工具
  10. CTR介绍,数据集往往为表格形式,训练集使用历史的日志数据,然后进行特征归一化、离散化和特征哈希等操作,最终一条训练集为一行多列的二分类任务。
  11. 【问题解决】nuget 打包 Unable to find “****.nupkg”.make sure the project has been built. 问题参考
  12. java 错误声音播放器_JavaME 声音播放器的使用
  13. 洛谷P3015 [USACO11FEB] Best Parenthesis
  14. 在搜索框里添加放大镜的图标,且显示提示信息
  15. WARNING: --master-data is deprecated and will be removed in a future version
  16. 国际期货和国内期货的区别带招商
  17. c++基于ffmpeg实现mp4转flv
  18. SQlServer的日期相减(间隔)dateadd ,datediff 函数
  19. 魔点人脸识别闸机系统落地郑州中心客运站
  20. 更改cognos upfront 的外观

热门文章

  1. 【LeetCode】专题一 二叉树层序遍历
  2. Pulsar Modular All Plug-Ins for mac 音频延迟插件
  3. 青年体检(肿瘤筛查)
  4. 动量效应 matlab,十万火急!!我的这个动量效应的R语言程序正确么??
  5. Quantum LeaPs(QP)介绍
  6. css草书,CSS emoji字体实现
  7. cisco路由器用户名密码破解
  8. 【转】电子工程师必须懂得如何规划自己的人生
  9. html整体页面缩放的方法,html5中让页面缩放的4种方法
  10. ios android跨服务器,《大话西游》手游_iOS安卓跨系统角色转移功能介绍_《大话西游》手游官网...