本章, 我们为你揭秘 Spring Boot 自动配置 (Auto Configuration) 运行机制, 谈到 auto-configuration, 肯定离不开 @EnableAutoConfiguration 注解.
- package org.springframework.boot.autoconfigure;
- @Target(ElementType.TYPE)
- @Retention(RetentionPolicy.RUNTIME)
- @Documented
- @Inherited
- @AutoConfigurationPackage
- @Import(EnableAutoConfigurationImportSelector.class)
- public @interface EnableAutoConfiguration {
- Class<?>[] exclude() default {
- };
- String[] excludeName() default {
- };
- }
这里涉及了两个元注解: @AutoConfigurationPackage, @Import(EnableAutoConfigurationImportSelector.class), 其中 @AutoConfigurationPackage 定义如下:
- package org.springframework.boot.autoconfigure;
- import ....
- @Target(ElementType.TYPE)
- @Retention(RetentionPolicy.RUNTIME)
- @Documented
- @Inherited
- @Import(AutoConfigurationPackages.Registrar.class)
- public @interface AutoConfigurationPackage {
- }
@AutoConfigurationPackage 注解定义中使用了 @Import 元注解, 注解属性 value 取值为 AutoConfigurationPackages.Registrar.class,AutoConfigurationPackages.Registrar 类实现了接口 ImportBeanDefinitionRegistrar
@Import 注解可以接受以下几种定义类型的 Java 类
使用 @Configuration 注解的类
ImportSelector 实现类: 以代码方式处理 @Configuration 注解类
DeferredImportSelector 实现类: 与 ImportSelector 类似, 区别在于处理操作被延迟到所有其他配置项都处理完毕再进行.
ImportBeanDefinitionRegistrar 实现类
AutoConfigurationPackages.Registrar 会向 Spring 容器注册 Bean,Bean 本身会存储用户自定义配置包列表. Spring Boot 本身会使用这个列表. 例如: 对于 spring-boot-autoconfigure 数据访问配置类, 可以通过静态方法: AutoConfigurationPackages.get(BeanFactory)来获取到这个配置列表, 下面是示例代码.
- package com.logicbig.example;
- import ...
- @EnableAutoConfiguration
- public class AutoConfigurationPackagesTest {
- public static void main (String[] args) {
- SpringApplication App =
- new SpringApplication(AutoConfigurationPackagesTest.class);
- App.setBannerMode(Banner.Mode.OFF);
- App.setLogStartupInfo(false);
- ConfigurableApplicationContext c = App.run(args);
- List<String> packages = AutoConfigurationPackages.get(c);
- System.out.println("packages:"+packages);
- }
- }
代码输出如下:
- 2017-01-03 10:17:37.372 INFO 10752 --- [ main] s.c.a.AnnotationConfigApplicationContext : Refreshing org.springframework.context.annotation.AnnotationConfigApplicationContext@67b467e9: startup date [Tue Jan 03 10:17:37 CST 2017]; root of context hierarchy
- 2017-01-03 10:17:38.155 INFO 10752 --- [ main] o.s.j.e.a.AnnotationMBeanExporter : Registering beans for JMX exposure on startup
- packages: [com.logicbig.example]
- 2017-01-03 10:17:38.170 INFO 10752 --- [ Thread-1] s.c.a.AnnotationConfigApplicationContext : Closing org.springframework.context.annotation.AnnotationConfigApplicationContext@67b467e9: startup date [Tue Jan 03 10:17:37 CST 2017]; root of context hierarchy
- 2017-01-03 10:17:38.171 INFO 10752 --- [ Thread-1] o.s.j.e.a.AnnotationMBeanExporter : Unregistering JMX-exposed beans on shutdown
@Import(EnableAutoConfigurationImportSelector.class)注解是 auto-configuration 机制的启动入口. EnableAutoConfigurationImportSelector 实现了接口 DeferredImportSelector, 其内部调用了 SpringFactoriesLoader.loadFactoryNames()方法, 方法会从 META-INF/spring.factories 中加载配置类.
- protected List<String> getCandidateConfigurations(AnnotationMetadata metadata,
- AnnotationAttributes attributes) {
- List<String> configurations = SpringFactoriesLoader.loadFactoryNames(
- getSpringFactoriesLoaderFactoryClass(), getBeanClassLoader());
- Assert.notEmpty(configurations,
- "No auto configuration classes found in META-INF/spring.factories. If you"
- + "are using a custom packaging, make sure that file is correct.");
- return configurations;
- }
从 spring.factories 中查找键值 org.springframework.boot.autoconfigure.EnableAutoConfiguration 的值:
spring-boot-autoconfigure 默认隐式包含在所有启动程序中
下面其中的一个配置类 JmxAutoConfiguration 的代码段
- package org.springframework.boot.autoconfigure.jmx;
- .......
- import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
- import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
- import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
- import org.springframework.boot.autoconfigure.condition.SearchStrategy;
- .....
- @Configuration
- @ConditionalOnClass({
- MBeanExporter.class
- })
- @ConditionalOnProperty(prefix = "spring.jmx", name = "enabled", havingValue = "true", matchIfMissing = true)
- public class JmxAutoConfiguration implements
- EnvironmentAware, BeanFactoryAware {
- .....
- }
- @ConditionalOnClass
@ConditionalOnClass 是由元注解 @Conditional(OnClassCondition.class 定义的注解, 我们知道,@Conditional 是条件注解, 只有条件为真时,@Conditional 注解的类, 方法才会被加载到 Spring 组件容器中. 对于上面的实例代码段, 只有当 MBeanExporter.class 已经包含在 classpath 中 (具体校验类似于 Class.forName 的加载逻辑, 当目标类包含在 classpath 中, 方法返回为 true, 否则返回 false),OnClassCondition#matches() 才会返回为 true.
@ConditionalOnProperty
与 @ConditionalOnClass 类似,@ConditionalOnProperty 是另一个 @Conditional 类型变量, 是由元注解 @Conditional(OnPropertyCondition.class)所定义的注解. 只有当目标属性包含了指定值, OnPropertyCondition#matches()才会返回真, 还是上面的代码段:
- @ConditionalOnProperty(prefix = "spring.jmx", name = "enabled",
- havingValue = "true", matchIfMissing = true)
如果我们应用配置了 spring.jmx.enabled=true, 那么
来源: http://blog.51cto.com/14226230/2421423