自动配置的使用
配置是Spring Framework的核心元素,必须要有东西告诉Spring如何应用程序。当你引入Spring Boot时,有个名为spring-boot-autoconfigure
的JAR文件,其中包含了很多配置类。每个配置类都在应用程序的Classpath里,当条件适当时就会启用这些配置类。
那么什么时候算是条件适当呢?
下面这张表格就是自动配置中使用的条件化注解,上面限定了一些配置生效条件。这是Spring 4.0提供的条件化配置,可以判断这个配置是该被应用还是被忽略.
举个例子
这是Spring Boot自动配置库中的一个数据源配置类。
这里添加了@ConditionOnClass({DataSource.class, EmbeddedDatabaseType.class})
注解,要求Classpath里必须有DataSource
和EmbeddedDatabaseType
.如果它们不存在,条件就不成立,DataSourceAutoConfiguration
提供的配置都会被忽略掉。
当你想要覆盖Spring Boot的自动配置,只需要写一个显示的配置类,添加@Configuration
注解,或是在xml文档中进行配置,Spring Boot会发现你的配置,使自动配置类不生效,以你的配置为准.
上表中的ConditionOnMissingBean
注解是覆盖自动配置的关键.举个覆盖自动配置的例子。
这是DataSourceAutoConfiguration
类中的一个方法,ConditionOnMissingBean({DataSource.class,XADataSource.class})
,要求当前不存在DataSource.class
、XADataSource.class
才生效.如果当前已经有了这两个Bean,条件既不满足,不会执行PooledDataSourceConfiguration
方法。
如果上面表格的条件化注解不适用时,可以实现Condition
接口的match()
方法,然后结合Conditional
注解自定义配置生效条件。
自动配置的源码分析
从上图可以看出SpringBoot的启动类上的注解SpringBootApplecation
都包含有EnableAutoConfiguration
注解,意味着启用自动配置。
跟进EnableAutoConfiguration
类中发现含有@Import({AutoConfigurationImportSelector.class})
注解,@Import
注解也是将类加载进Spring容器中,这里导入了类AutoConfigurationImportSelector
字面意思上看是一个自动配置导入的选择器类。
上图可以看出,自动配置大致可以分为三步。
- 检查注解是否开启
- 读取自动配置元数据,其实就是自动配置类的注解属性
- 获取符合条件的自动配置类
第一步,注解是否开启
这步其实就是获取环境变量,将注解类的值进行比较。
第二步,读取自动配置元数据
跟进方法
META-INF/spring-autoconfigure-metadata.properties里头放了定义了很多默认自动配置类的关联配置类以及生效条件的指定类.
这有一个selectImports
方法,通过loadMetadata()
方法加载META-INF/spring-autoconfigure-metadata.properties,存放到内部静态类AutoConfigurationEntry
中,这个类存放了配置类的类名以及需要排除的类名.
第三步,执行getAutoConfigurationEntry()
方法,根据第二步读取的自动配置类的注解属性,开始获取需要生效的配置类列表。
这一步其实就是根据自带的两个配置文件spring-autoconfigure-metadata.properties
、spring.factories
加载自动配置类、及自动配置类生效的条件,根据这些内容去过滤一些不符合条件、重复的自动配置类,最后返回一个需要生效的自动配置类列表。
什么时候执行selectImports()
?
Spring boot应用启动过程中使用ConfigurationClassParser
分析配置类 (比如使用了@Configuration
的注解类)时,如果发现注解中存在@Import(AutoConfigurationImportSelector.class)
的情况,就会创建一个相应的AutoConfigurationImportSelector
对象, 并调用其selectImports(AnnotationMetadata annotationMetadata
对象方法public String[] selectImports(AnnotationMetadata annotationMetadata)
。
这里 @EnableAutoConfiguration
的导入@Import(EnableAutoConfigurationImportSelector.class)
就属于这种情况【发现有@import注解,那么就对该导入类进行一个事例化】,所以ConfigurationClassParser会实例化一个 EnableAutoConfigurationImportSelector 并调用它的 selectImports() 方法。
Spring的工具类ConfigurationClassParser用于分析@Configuration注解的配置类,产生一组ConfigurationClass对象。它的分析过程会接受一组种子配置类(调用者已知的配置类,通常很可能只有一个),从这些种子配置类开始分析所有关联的配置类,分析过程主要是递归分析配置类的注解@Import,配置类内部嵌套类,找出其中所有的配置类,然后返回这组配置类。
该工具主要由ConfigurationClassPostProcessor使用,而ConfigurationClassPostProcessor是一个BeanDefinitionRegistryPostProcessor/BeanFactoryPostProcessor,它会在容器启动过程中,应用上下文上执行各个BeanFactoryPostProcessor时被执行。