SpringBoot消息源碼解析:JMS基礎(chǔ)自動(dòng)配置
SpringBoot消息源碼解析
Spring框架對(duì)消息系統(tǒng)的整合提供了廣泛的支持:從簡(jiǎn)單使用 Jms Template 的 JMS API,到可接收異步消息的完整基礎(chǔ)結(jié)構(gòu)。Spring AMQP 為“高級(jí)消息隊(duì)列協(xié)議”提供了類似的功能集。
同時(shí),Spring Boot 也為 RabbitTemplate 和 Rabbit MQ 提供了自動(dòng)配置選項(xiàng)。Spring Boot通過(guò)自動(dòng)配置對(duì) ActiveMQ、RabbitMQ 和 Apache Kafka 提供了支持。本章重點(diǎn)講解 SpringBoot 對(duì) JMS 和 ActiveMQ 的自動(dòng)配置操作。
JMS 基礎(chǔ)自動(dòng)配置
JMS 的全稱是 Java Message Service,即 Java 消息服務(wù)。它主要用于在生產(chǎn)者和消費(fèi)者之間進(jìn)行消息傳遞。JMS 只是一個(gè)標(biāo)準(zhǔn), 在使用的時(shí)候需要有具體實(shí)現(xiàn),比如后面要講到的ActiveMQ。
在 Spring Boot 中,通過(guò) JmsAutoConfiguration 自動(dòng)配置來(lái)完成 JMS 的基礎(chǔ)組件的初始化。
像其他自動(dòng)配置-樣,在 ME TA-INF/spring.factories 中可以找到注冊(cè)的 JMS 自動(dòng)配置類。
# Auto Configure
org. springframework . boot . autoconfigure . jms . JmsAutoConfiguration
JmsAutoConfiguration 的注解
我們先從 JmsAutoConfiguration 的注解部分看起。
@Configuration(proxyBeanMethods = false)
@Conditional0nClass({ Message . class, JmsTemplate.class })
@ConditionalOnBean(ConnectionFactory . class)
@EnableConfigurationProperties (JmsProperties .class)
@Import (JmsAnnotat ionDrivenConfiguration. class)
public class JmsAutoConfiguration {
}@ConditionalOnClass 注解指定需要滿足在 classpath 下存在javax.jms.Message 類和
org.springframework.jms.core.Jms Template 類的條件才會(huì)進(jìn)行初始化。
@ConditionalOnBean 注解指定需要在容器中存在
javax.jms.ConnectionFactory 的 Bean 對(duì)象時(shí)才會(huì)被實(shí)例化。
ConnectionFactory 接口提供了用于創(chuàng)建與 JMS 代理進(jìn)行交互的 javax.jms.Connection 的標(biāo)準(zhǔn)方法。Spring 需要 ConnectionFactory 來(lái) 與 JMS 一起使用,但是通常不需要編程人員直接使用它。
那么,ConnectionFactory 的 Bean 是在什么時(shí)候被初始化的呢?以 ActiveMQ 為例,Active-MQ 的自動(dòng)配置會(huì)在 JmsAutoConfiguration 配置之前執(zhí)行,并在其內(nèi)部創(chuàng)建Connection-Factory 實(shí)現(xiàn)類的 Bean 對(duì)象。其他消息框架也與此類似,至于是如何初始化的,后面關(guān)于 ActiveMQ 的自動(dòng)配置的部分我們會(huì)進(jìn)行詳解。
@
EnableConfigurationProperties引入了JMS的配置屬性類 ,對(duì)應(yīng)的就 是 在application.properties 文件中配置的以“spring.jms”為前綴的屬性。
@Import 引入了
JmsAnnotationDrivenConfiguration 配置,該配置類主要用于 Spring4.1 注解驅(qū)動(dòng)的 JMS 的自動(dòng)配置。
下面我們先看
JmsAnnotationDrivenConfiguration 的注解部分和構(gòu)造方法的源代碼。
@Configuration(proxyBeanMethods = false)
@ConditionalOnClass (EnableJms .class)class JmsAnnotationDrivenConfiguration {
private final objectProvider destinat ionResolver;
private final objectProvider transactionManager J
private final objectProvider messageConverter;
private final JmsProperties properties;
JmsAnnotationDrivenConfiguration(ObjectProvider dest
ination-
Resolver,
ObjectProvider tr
ansactionManager, 0bject-
Provider messageConver
ter,
JmsProperties properties) {
this . destinationResolver = destinationResolver;
this. transactionManager = transactionManager;
this . messageConverter = messageConverter;
this. properties = properties;
}
} @Configuration 聲 明 該 類 也 是 配 置 類 , @ConditionalOnClass 表 示 類 路 徑 下 需 存 在EnableJms 類。其中 EnableJms 為一個(gè)注解類,@EnableJms 用于開(kāi)啟 JMS 注解,使@JmsListener 注解生效。
在之前章節(jié)已經(jīng)講過(guò)
JmsAnnotationDrivenConfiguration 的構(gòu)造方法中 ObjectProvider 的作用,這里看其泛型部分類。其中 JmsProperties 參數(shù)為 JMS 的配置,前面已經(jīng)提到過(guò),下 面我們重點(diǎn)看其他 3 個(gè)參數(shù)。
DestinationResolver 用于解決 JMS 目標(biāo)的策略接口,被 Jms Template 用于將目標(biāo)名稱從簡(jiǎn)單的字符串解析為實(shí)際的 Destination 實(shí)現(xiàn)實(shí)例。JmsTemplate 實(shí)例使用的默認(rèn)Destina-tionResolver 實(shí)現(xiàn)
DynamicDestinationResolver 類。
該接口只有一個(gè)方法, 通過(guò)源代碼可以更清晰地看出它的功能。
@FunctionalInterface
public interface Dest inationResolver
//將給定的目標(biāo)名稱解析為定位資源或作為動(dòng)態(tài)的 Destinat ion(返回 topic 或 queue)
// Session: 為當(dāng)前 JMS 的 Session
// destinat ionName:目標(biāo)名稱
// pubSubDomain: true 表示 pub-sub 模式,false 表示 P2P 模式
Destination resolveDestinationName (@Nullable Session session, String destina-tionName, boolean pubSubDomain) throws
JMSException;
}Jta TransactionManager 是
PlatformTransactionManager 的實(shí)現(xiàn)類,它提供了 Spring 的JTA 事務(wù)管理,也可用于分布式事務(wù)的管理。關(guān)于事務(wù)相關(guān)的內(nèi)容,在此不進(jìn)行展開(kāi)。
MessageConverter 是一個(gè)策略接口, 用于指定 Java 對(duì)象和 JMS 消息之間的轉(zhuǎn)換器。
SimpleMessageConverter 作 為 其 簡(jiǎn) 單 的 默 認(rèn) 實(shí) 現(xiàn) , 能 夠 處 理 TextMessages 、BytesMessages、 MapMessages 和 ObjectMessages 之 間的消息轉(zhuǎn)換。
public interface MessageConverter {
//轉(zhuǎn)換 Java 對(duì)象到 JMS 消息
Message toMessage(object
object,
Session
session)
throws
JMSException,
MessageConversionException;
//轉(zhuǎn) JMS 消息為 Java 對(duì)象
Object fromMessage (Message message) throws JMSException, MessageConversio
nException;
}通過(guò) MessageConverter 接口方法的定義也能夠看出它的核心功能就是進(jìn)行 Java 對(duì)象與JMS 消息之間的轉(zhuǎn)換。
了解完構(gòu)法我們先看
DefaultJmsListenerContainerFactoryConfigurer 的初始化,代碼如下。
@Bean
@ConditionalOnMissingBean
DefaultJmsListenerContainerFactoryConfigurer jmsL istenerContainerFactoryCon
rer() {
DefaultJmsL istenerContainerF actoryConfigurer configurer = new DefaultJmsL
is -
tenerContainerFactoryConfigurer();
configurer . setDestinationResolver(this . destinationResolver . getIfUnique
());
configurer . setTransactionManager(this . transactionManager . getIfUnique());
configurer . setMessageConverter(this . messageConverter . getIfUnique());
configurer . setJmsProperties (this . properties);
return configurer;
}初始化操作就是創(chuàng)建一個(gè)
DefaultJmsListenerContainerFactoryConfigurer 對(duì)象,然后將上面構(gòu)造方法傳入的參數(shù)設(shè)置到 DefaultJmsListenerContainerFactoryConfigurer 對(duì)象中。該類的作用是配置DefaultJmsListenerContainerFactory通過(guò)DefaultJmsListenerContainerFact-oryConfigurer 中的 configure 方法將構(gòu)造方法中的參數(shù)項(xiàng)賦值給 DefaultJmsListenerContainer-Factory.而 DefaultJmsListenerContainerFactory是個(gè) JmsListenerContainerFactory 實(shí)現(xiàn),
用于構(gòu)建常規(guī)的 DefaultMessageL istenerContainer。對(duì)于大多數(shù)用戶,這是默認(rèn)設(shè)置,對(duì)于用于手動(dòng)構(gòu)建此類容器定義的用戶,這應(yīng)該是一個(gè)很好的過(guò)渡路徑。
接下來(lái)便是
DefaultJmsListenerContainerFactory 的初始化操作,代碼如下。
@Bean
@ConditionalOnSingleCandidate(Connect ionFactory. class)
@ConditionalOnMissingBean(name = "jimsListenerContainerFactory")
DefaultJmsListenerContainerFactory jmsListenerContainerFactory(
DefaultJmsListenerContainerF actoryConfigurer configurer, ConnectionFactory
connectionFactory) {
DefaultImsListenerContainerFactory factory = new DefaultJmsL istenerContai
nerFactory();
configurer . configure(factory, connectionFactory);
return factory;
}當(dāng)存在唯一候選 ConnectionFactory 的 Bean 并且當(dāng) name 為
jmsListenerContainer-Factory的 DefaultJmsListenerContainerFactory Bean 不存在時(shí),會(huì)執(zhí)行創(chuàng)建和初始化操作。其中創(chuàng)建就是直接 new-一個(gè)對(duì)象,而關(guān)于初始化操作,上面已經(jīng)提到了,通過(guò) DefaultJms-ListenerContainerFactoryConfigurer 的 configure 方法來(lái)對(duì) DefaultJmsListenerContainerFacto-ry 對(duì)應(yīng)的各項(xiàng)參數(shù)進(jìn)行賦值。
JmsAnnotationDrivenConfiguration 剩余部分代碼定義了兩個(gè)內(nèi)部類,代碼如下。
@Configuration(proxyBeanMethods = false)
@EnableJms
@ConditionalOnMissingBean(name = JmsL istenerConfigUtils.JMS_ LISTENER NNOTA
TION_
PROCESSOR_ BEAN NAME)
static class EnableJmsConfiguration
@Configuration(proxyBeanMethods = false)
@Conditional0nJndi
static class IndiConfiguration {
@Bean
@Conditiona lOnMissingBean(DestinationResolver. class)
JndiDestinationResolver dest inationResolver() {
JndiDestinationResolver resolver = new JndiDestinationResolver();resolver . setFallbackToDynamicDestination(true);
return resolver;
}
}其 中 , 內(nèi) 部 類 EnableJmsConfiguration 的 實(shí) 現(xiàn) 為 空 , 主 要 作 用 是 根 據(jù) 條 件 來(lái) 使@EnableJms 注解生效生效條件是類
org.springframework.jms.config.internalJmsListenerAnnotation-Processor 對(duì)應(yīng)的 Bean 不存在。
內(nèi)部類 JndiConfiguration 主要實(shí)例化了 JndiDestinationResolver,JndiDestinationResolver 是我們上面講到的 DestinationResolver 具體實(shí)現(xiàn),用于將目標(biāo)名稱解釋為 JNDI 位置。
至此,關(guān)于 JmsAutoConfiguration 注解部分, 及其注解部分的延伸內(nèi)容已經(jīng)講解完畢。下一 節(jié), 我們繼續(xù)學(xué)習(xí) JmsAutoConfiguration 內(nèi)部的自動(dòng)配置實(shí)現(xiàn)。
JmsAutoC onfiauration 內(nèi)部實(shí)現(xiàn)
JmsAutoConfiguration 的內(nèi)部代碼部分主要包含兩個(gè)內(nèi)部靜態(tài)類:Jms' TemplateConfi-guration 和 Messaging TemplateConfiguration。
Jms' TemplateConfiguration 主要用來(lái)初始化 Jms Template 對(duì)象。它的構(gòu)造方法主要設(shè)置了JmsProperties、ObjectProvider
下面看 Jms TemplateConfiguration 中 Jms Template 的初始化。
@Configuration(proxyBeanMethods = false)
protected static class Jms TemplateConfiguration {
.. .
@Bean
@Condit ionalOnMissingBean
@ConditionalOnSingleCandidate(ConnectionFactory. class)
public Jms Template jmsTemplate(ConnectionFactory connectionFactory) {
PropertyMapper map = PropertyMapper .get();
//基于 ConnectionFactory 創(chuàng)建 Jms Template 對(duì)象
JmsTemplate template = new Jms Template( connectionFactory);
//沒(méi)置是否為發(fā)布訂閱模式
template . setPubSubDomain(this . properties . isPubSubDomain());
map . from(this . dest inat ionResolver: :getIfUnique ) . whenNonNull()
. to(template: :setDestinationResolver);
map . from(this . messageConverter :: getIfUnique) . whenNonNull(). to(template: :setMessageConverter);
mapTemplateProperties(this . properties . getTemplate(),template);
return template;
private void mapT emplateProperties (Template properties, JmsTemplate templ
ate)
//... Template 的其他參數(shù)設(shè)置
}
}在初始化 JmsTemplate 的過(guò)程中,明確要求必須只有一個(gè)候選 ConnectionFactory 對(duì)象存在,并且不存在 Jms Template 對(duì)象。
Jms Template 是用于簡(jiǎn)化同步 JMS 訪問(wèn)代碼的 Helper 類。以上代碼業(yè)務(wù)比較簡(jiǎn)單,就是創(chuàng) 建 了 JmsTemplate 對(duì) 象 , 并 判 斷 DestinationResolver 、 MessageConverter 和JmsPro-perties 中的值是否為 null,如果不為 null 則對(duì) Jms Template 進(jìn)行賦值。
其中值得注意的是 Jms Template 的 pubSubDomain 的設(shè)置,默認(rèn)情況下為 false,即 P2P模 式 (Point-to-Point
另外一個(gè)內(nèi)部類 Messaging TemplateConfiguration 用來(lái)創(chuàng)建 JmsMessaging Template 對(duì)象。
@Configuration(proxyBeanMethods = false)
@ConditionalOnClass (JmsMessagingTemplate. class)
@Import(JmsTemplateConfiguration. class)
protected static class MessagingTemplateConfiguration {
@Bean
@ConditionalOnMiss ingBean( JmsMessageOperations. class)
@ConditionalOnSingleCandidate(Jms Template. class)
public JmsMessagingTemplate jmsMessagingTemplate(JmsProperties propertie
s,JmsTemplate
jmsTemplate) {
JmsMessagingTemplate messagingTemplate = new JmsMessagingTemplate(jms -
Templ
ate);
//沒(méi)置目標(biāo)名稱
mapTemplateProperties(properties . getTemplate(), messagingTemplate);p
return
messagingTemplate;
private void mapTemplateProperties (Template properties, JmsMessagingTemplatemessagingTemplate) {
PropertyMapper map = PropertyMapper . get(). alwaysApplyingWhenNonNu1l();
/沒(méi)置目標(biāo)名稱
map. from(properties : :getDefaultDestination) . to(messagingTemplate: : setDe
fault-
DestinationName);
}
}當(dāng)類路徑下有 JmsMessagingTemplate 時(shí)才會(huì)觸發(fā)
MessagingTemplateConfiguration 的自動(dòng)配置。通過(guò)@lmport 注解引入了上面井到的 Jms TemplateConfiguration 配置類, 為了確保 Jms Template 的實(shí)例化,創(chuàng)建、JmsMessagingTemplate 時(shí)將 Jms Template 對(duì)象作為參數(shù), 然后設(shè)置目標(biāo)名稱。
JmsMessagingTemplate 為 JmsMessageOperations 的具體實(shí)現(xiàn),也是提共 Spring 發(fā)送消息的工具類。自 Spring 4.1 起,JmsMessaging Template 構(gòu)建于 JmsTemplate 之上,提供了消息抽象的集成,例如
rg.springframework.messaging.Message。
至此,JmsAuto( Confiauration 相關(guān)的自動(dòng)配置講解完畢,也完成了 JMS 基礎(chǔ)的自動(dòng)配置。
本文給大家講解的內(nèi)容是SpringBoot消息源碼解析:JMS基礎(chǔ)自動(dòng)配置
下篇文章給大家講解的是以ActiveMQ為例,講解其自動(dòng)配置的實(shí)現(xiàn);
覺(jué)得文章不錯(cuò)的朋友可以轉(zhuǎn)發(fā)此文關(guān)注小編;
感謝大家的支持!

本文就是愿天堂沒(méi)有BUG給大家分享的內(nèi)容,大家有收獲的話可以分享下,想學(xué)習(xí)更多的話可以到微信公眾號(hào)里找我,我等你哦。
