上文说到,当我们的主方法启动时,标有 @SpringBootApplication 注解的主类(实际起到自动装配功能的为其父注解 @EnableAutoConfiguration)会加载其父注解中 @Import 里配置的 ImportSelector 接口的实现类 AutoConfigurationImportSelector,调用其中的方法,加载处于 spring-boot-autoconfigure 包下的 META-INF/spring.factories 配置文件加载默认的配置类,并在 AutoConfigurationSeletor#fireAutoConfigurationImportEvents 方法中发布 AutoConfigurationImportEvent 事件,使得监听器得以注册默认配置类完成自动装配原理。
那么问题就来了,spring.factories 这个文件中的配置类何德何能完成 分析依赖项、读取配置文件、自动生成配置Bean 的功能呢?我们继续探寻。
随便点入一个文件中的自动装配配置类,我们通常可以看到以下关键注解:
@Configuration
顾名思义,这个注解标注了该类为一个 Spring 注解配置类,这也是该类得以被扫描注册的根本原因
@AutoConfigureBefore 与 @AutoConfigureAfter
显然,这两个注解的意义在于为自动装配类提供一个显示声明的装配顺序选项,但它明显不是我们索要研究的重点,让我们继续看下去。
@ConditionalOnClass 与 @ConditionalOnMissingBean
Conditional 意“有条件的”,不止这两个。在 org.springframework.boot.autoconfigure.condition 包下有许许多多其它的 ConditionOnXx 注解,通过翻看源码的注释我们可以得知,当且仅当被 @Configuration 标注的配置类满足所有 @ConditionalOnXx 注解(有的是环境中存在对应类,有的是环境中存在对应Bean),该配置文件类才会被加载到容器中,以下以 @ConditionalOnClass 为例:
红框内容:仅指定的类存在于类路径中时匹配条件
由此可见,那些我们未加载的默认配置类在这些或检测运行环境,或检测配置的注解作用下以这种巧妙的方式取消了自动装载,保证了容器的高可用性。
@EnableConfigurationProperties 于 XXXProperties.class
翻看 @EnableConfigurationProperties 的注解,我们可用看到这样一段话
大致意思为使用此注解配置的,标注了 @ConfigurationProperties 注解的类,将会以标注化的形式注册成为 Bean。即该注解起到便于统一注册与标识特定配置类的作用。基于上述我们不难猜测,在 @EnableConfigurationProperties 注解中配置的 ActiveMQProperties.class 与 JmsProperties.class 类上都打上了 @ConfigurationProperties 注解(且无 @Component 注解)
对于 @ConfigurationProperties 注解相比大家不会陌生,该注解的功能是将容器中指定配置路径下所有配置属性注入被标注的实体类的一种配置类注解,常用于进行全局参数文件加载或解耦的默认实体类的生成。
转到 ActiveMQProperties.class,该类唯一的一个注解便是先前提到的 @ConfigurationProperties,其 prefix 属性为 spring.activemq,往下查找,也能发现许多未被初始化的成员变量:
我们知道,@ConfigurationProperties 注解中的 prefix 属性标注了该配置文件在容器配置文件路径中的节点位置,而以 spring 为前缀配置文件我们一般在 application 文件中配置,来到 application(此处演示以 yaml 格式进行),我们发现果然有以 spring.activemq 为父节点的可配置的片段,其属性名也与 ActiveMQProperties.class 中的成员变量名吻合:
总结
进行到此处,我们不难得出以下结论
- spring.factories 中的自动装配配置类中以 @ConditionalXx 注解指定加载前提,若未达条件则不会进一步解析装配该配置文件类
- 配置文件类以 @EnableConfigurationProperties 注解统一管理加载使用了 @ConfigurationProperties 注解的实体配置类,该类在加载时会扫描容器中所有配置文件 Bean 中指定路径下的数据片段并将其注入,实现配置文件的自动加载。