【源码阅读】看Spring Boot如何自动装配ActiveMQ收发组件

源于好奇,我研究了一下Spring Boot中ActiveMQ相关组件是如何自动装配的。记录如下。

源码路径

本文以Spring Boot 1.5.10.RELEASE版本为例。

在spring-boot-autoconfigure-1.5.10.RELEASE.jar中的spring.factories文件中可以找到相JMS自动装配类。

org.springframework.boot.autoconfigure.jms.JmsAutoConfiguration,\
org.springframework.boot.autoconfigure.jms.JndiConnectionFactoryAutoConfiguration,\
org.springframework.boot.autoconfigure.jms.activemq.ActiveMQAutoConfiguration,\

在spring-jms-4.3.14.RELEASE.jar中包含了jms组件的所有具体功能类。

Configuration类加载顺序

顺序 类名 import引入
1 JndiConnectionFactoryAutoConfiguration
2 ActiveMQAutoConfiguration ActiveMQXAConnectionFactoryConfiguration, ActiveMQConnectionFactoryConfiguration
3 JmsAutoConfiguration JmsAnnotationDrivenConfiguration, JmsBootstrapConfiguration(由JmsAnnotationDrivenConfiguration中的@EnableJms注解引入)

以上罗列出了与ActiveMQ相关的配置类,默认ActiveMQ是采用JMS协议连接的。Spring的JMS消息组件接收与发送是毫不相关的体系。下文分别阐述。

关键类列表

类名 类别 作用
JmsProperties Properties注入 spring.jms开头的配置项注入
ActiveMQProperties Properties注入 spring.activmeq开头的配置项注入
ActiveMQAutoConfiguration @Configuration 无具体代码,通过注解引入ActiveMQXAConnectionFactoryConfiguration与ActiveMQConnectionFactoryConfiguration两个配置类
ActiveMQXAConnectionFactoryConfiguration @Configuration 配置ActiveMQ XA(点击这里了解XA)连接工厂
ActiveMQConnectionFactoryConfiguration @Configuration 配置ActiveMQ连接工厂
JmsAutoConfiguration @Configuration 与发送消息组件相关,初始化JmsTemplate与JmsMessagingTemplate(Spring4.1后引入)
JmsAnnotationDrivenConfiguration @Configuration 与接收消息组件相关,初始化JmsListenerContainerFactory
JmsBootstrapConfiguration @Configuration 初始化JmsListenerAnnotationBeanPostProcessor 与JmsListenerEndpointRegistry两个类的Bean
JmsListenerAnnotationBeanPostProcessor Bean 自定义JmsListenerEndpointRegistrar行为,并将带有@JmsListener的方法注册到指定的JmsListenerContainerFactory中。
JmsListenerEndpointRegistrar Bean 将JmsListenerEndpoint对象注册到JmsListenerEndpointRegistry对象中。

发送消息

发送消息组件的装配相对简单,主要代码都在ActiveMQConnectionFactoryConfigurationJmsAutoConfiguration两个类中。

ActiveMQConnectionFactoryConfiguration

class ActiveMQConnectionFactoryConfiguration {

    @Bean
    @ConditionalOnProperty(prefix = "spring.activemq.pool", name = "enabled", havingValue = "false", matchIfMissing = true)
    public ActiveMQConnectionFactory jmsConnectionFactory(ActiveMQProperties properties,
            ObjectProvider<List<ActiveMQConnectionFactoryCustomizer>> factoryCustomizers) {
        ...
    }

    @Bean(destroyMethod = "stop")
    @ConditionalOnProperty(prefix = "spring.activemq.pool", name = "enabled", havingValue = "true", matchIfMissing = false)
    @ConfigurationProperties(prefix = "spring.activemq.pool.configuration")
    public PooledConnectionFactory pooledJmsConnectionFactory(
                ActiveMQProperties properties,
                ObjectProvider<List<ActiveMQConnectionFactoryCustomizer>> factoryCustomizers) {
            ...
    }

}

可以看到,此类根据配置项的不同初始化了ActiveMQ的连接工厂ActiveMQConnectionFactory或PooledConnectionFactory。

JmsAutoConfiguration

public class JmsAutoConfiguration {

    @Configuration
    protected static class JmsTemplateConfiguration {
        ...
        @Bean
        @ConditionalOnMissingBean
        @ConditionalOnSingleCandidate(ConnectionFactory.class)
        public JmsTemplate jmsTemplate(ConnectionFactory connectionFactory) {
            ...
        }
    }

    @Configuration
    @ConditionalOnClass(JmsMessagingTemplate.class)
    @Import(JmsTemplateConfiguration.class)
    protected static class MessagingTemplateConfiguration {

        @Bean
        @ConditionalOnMissingBean
        @ConditionalOnSingleCandidate(JmsTemplate.class)
        public JmsMessagingTemplate jmsMessagingTemplate(JmsTemplate jmsTemplate) {
            return new JmsMessagingTemplate(jmsTemplate);
        }
    }
}

从源码中可以看到,JmsAutoConfiguration主要作用是当JmsTemplateJmsMessagingTemplate两个类的对象不存在(没有由用户定义)时,初始化这两个类的默认Bean。

至此JMS消息发送关键组件初始化完成。用户可以通过Spring获得JmsTemplateJmsMessagingTemplate对象发送消息。

接收消息

Spring Boot接收消息的方法有好几种(具体请参阅),最简单与常用的方式就是使用@JmsListener注解在方法上。

Spring为每个带有@JmsListener注解的方法在后台构建了一个对应的MessageListenerContainer实例(老版本的Spring需要手动配置DefaultMessageListenerContainer,这里不再赘述)。

为了能自动创建MessageListenerContainer,Spring提供了@EnableJms注解,通过JmsListenerAnnotationBeanPostProcessorBeanPostProcessor机制,指定带有@JmsListener注解的方法为一个MethodJmsListenerEndpoint,并将其通过JmsListenerEndpointRegistrar辅助类注册到JmsListenerEndpointRegistry中。此过程中,需要一个JmsListenerContainerFactory对象(由用户自定义创建或由Spring自动创建DefaultJmsListenerContainerFactory)来参与完成构建动作。几个关键类的关系图大致如下。

JmsListener注册关键类结构图

另外,用户也可以通过实现JmsListenerConfigurer来指定JmsListenerEndpointRegistrar对象在注册过程中的行为。

下面看一下几个核心类的代码。

JmsListenerAnnotationBeanPostProcessor

public class JmsListenerAnnotationBeanPostProcessor
        implements MergedBeanDefinitionPostProcessor, Ordered, BeanFactoryAware, SmartInitializingSingleton {
...
        public Object postProcessAfterInitialization(final Object bean, String beanName) throws BeansException {
        ....
                for (Map.Entry<Method, Set<JmsListener>> entry : annotatedMethods.entrySet()) {
                    Method method = entry.getKey();
                    for (JmsListener listener : entry.getValue()) {
                        processJmsListener(listener, method, bean);
                    }
                }
        ...
        }

        protected void processJmsListener(JmsListener jmsListener, Method mostSpecificMethod, Object bean) {
        ...
                this.registrar.registerEndpoint(endpoint, factory);
        }

从以上的源码片段可以看出,JmsListenerAnnotationBeanPostProcessor的主要作用是将带有@JmsListener的方法(Endpoint)注册到JmsListenerContainerFactory中。

JmsAnnotationDrivenConfiguration

class JmsAnnotationDrivenConfiguration {
...
    @Bean
    @ConditionalOnMissingBean
    public DefaultJmsListenerContainerFactoryConfigurer jmsListenerContainerFactoryConfigurer() {
        ...
    }

    @Bean
    @ConditionalOnMissingBean(name = "jmsListenerContainerFactory")
    public DefaultJmsListenerContainerFactory jmsListenerContainerFactory(
            DefaultJmsListenerContainerFactoryConfigurer configurer,
            ConnectionFactory connectionFactory) {
        ...
    }
...
}

从源码可以看出,JmsAnnotationDrivenConfiguration主要作用是当名称为“jmsListenerContainerFactory”的bean不存在时初始化一个DefaultJmsListenerContainerFactory。

至此,接收消息的组件装配过程分析已完成。加上对应的配置项,用户可以从ActiveMQ中收到消息。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 214,100评论 6 493
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 91,308评论 3 388
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 159,718评论 0 349
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 57,275评论 1 287
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 66,376评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,454评论 1 292
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,464评论 3 412
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,248评论 0 269
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,686评论 1 306
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,974评论 2 328
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,150评论 1 342
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,817评论 4 337
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,484评论 3 322
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,140评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,374评论 1 267
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,012评论 2 365
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,041评论 2 351

推荐阅读更多精彩内容