Spring AMQP 源码--RabbitTemplate CachingConnectionFactory

version: 2.3.7.RELEASE

以发送消息为代码阅读入口, 消息发送方法 `org.springframework.amqp.rabbit.core.RabbitTemplate#convertAndSend(java.lang.String, java.lang.String, java.lang.Object)`

创建 `RabbitTemplate` 实例依赖 `org.springframework.amqp.rabbit.connection.CachingConnectionFactory`, 索引首先要创建 `CachingConnectionFactory` 实例

1. CachingConnectionFactory 实例化

`CachingConnectionFactory` 的构造方法 `org.springframework.amqp.rabbit.connection.CachingConnectionFactory#CachingConnectionFactory(java.lang.String, int)` 做了如下工作:

  1. 第257行, `newRabbitConnectionFactory()` 创建一个 `com.rabbitmq.client.ConnectionFactory` 实例, 设置  `automaticRecovery` 为 false 然后通过 `AbstractConnectionFactory` 的构造方法赋值给 `org.springframework.amqp.rabbit.connection.AbstractConnectionFactory#rabbitConnectionFactory`

  2. 第264行, 初始化 `org.springframework.amqp.rabbit.connection.CachingConnectionFactory#publisherConnectionFactory`, 用于为生产者创建 connection

  3. 第265行, 初始化父类 `org.springframework.amqp.rabbit.connection.AbstractConnectionFactory#publisherConnectionFactory` 为 `this.publisherConnectionFactory`

 2. 创建 connection

消息发送调用 `org.springframework.amqp.rabbit.core.RabbitTemplate#doExecute` 方法. 

在下图第2089行, `connection = ConnectionFactoryUtils.createConnection(connectionFactory, this.usePublisherConnection);` 创建`org.springframework.amqp.rabbit.connection.Connection`

调用 `org.springframework.amqp.rabbit.connection.CachingConnectionFactory#createConnection`

调用 `org.springframework.amqp.rabbit.connection.AbstractConnectionFactory#createBareConnection`, 在 `createBareConnection` 方法中看到

  1. `com.rabbitmq.client.Connection rabbitConnection = connect(connectionName);` 创建了一个 rabbitmq connection

  2. 把 `com.rabbitmq.client.Connection` 赋值给 `org.springframework.amqp.rabbit.connection.SimpleConnection#delegate`

  3. `createBareConnection` 方法返回 `org.springframework.amqp.rabbit.connection.SimpleConnection` 实例.

回到 `org.springframework.amqp.rabbit.connection.CachingConnectionFactory#createConnection` 可以看到:

  1. 把 `org.springframework.amqp.rabbit.connection.SimpleConnection` 赋值给 `org.springframework.amqp.rabbit.connection.CachingConnectionFactory.ChannelCachingConnectionProxy#target`

  2. `createConnection` 方法返回 `org.springframework.amqp.rabbit.connection.CachingConnectionFactory.ChannelCachingConnectionProxy` 实例.

回到第2089行 `connection = ConnectionFactoryUtils.createConnection(connectionFactory, this.usePublisherConnection);`, 可以确认这里的 `connection` 是一个 `ChannelCachingConnectionProxy` 实例.

 

 3. 创建 channel

在上图第2095行, `channel = connection.createChannel(false);` 创建 channel

调用 `org.springframework.amqp.rabbit.connection.CachingConnectionFactory.ChannelCachingConnectionProxy#createChannel`

调用 `org.springframework.amqp.rabbit.connection.CachingConnectionFactory#getChannel`

在下图557行, `determineChannelList(connection, transactional);` 返回 `cachedChannelsNonTransactional` 是空的 LinkedList`

在下图567行, `channel = getCachedChannelProxy(connection, channelList, transactional);` 创建 `org.springframework.amqp.rabbit.connection.ChannelProxy`

调用 `org.springframework.amqp.rabbit.connection.CachingConnectionFactory#createBareChannel`

调用 `org.springframework.amqp.rabbit.connection.CachingConnectionFactory#doCreateBareChannel`

调用 `org.springframework.amqp.rabbit.connection.SimpleConnection#createChannel`, 通过 `Channel channel = this.delegate.createChannel()` 创建 channel, 从上面我们已经知道 ` this.delegate` 是 `com.rabbitmq.client.Connection` 实例

回到第567行, `org.springframework.amqp.rabbit.connection.CachingConnectionFactory#getCachedChannelProxy` 方法

  1. 通过 Java 动态代理生成 `org.springframework.amqp.rabbit.connection.ChannelProxy` 的代理对象,  `org.springframework.amqp.rabbit.connection.ChannelProxy` 继承 `com.rabbitmq.client.Channel`

  2. 返回代理对象.

  #: 简单理解就是 `ChannelProxy` 代理 `Channel`, 在调用接口方法时改变已有的处理逻辑. 详细处理可以看 `org.springframework.amqp.rabbit.connection.CachingConnectionFactory.CachedChannelInvocationHandler#invoke`, 

  比如重写了 Channel 的 close() 方法, 根据条件把 channle 缓存了起来.

回到上图第2119行, finally里 `cleanUpAfterAction(channel, invokeScope, resourceHolder, connection);`, 最后会调用 `com.rabbitmq.client.Channel#close()` 方法.

posted @ 2022-03-16 16:44  景岳  阅读(502)  评论(0编辑  收藏  举报