众所周知,springboot的出现为开发带来了很大的方便,主要就是提供了很多自动配置,免去了开发人员花在配置上的时间,使我们开发者能更专注于业务或者架构设计上。
而springboot的自动配置是通过一系列注解来完成的,例如@EnableAutoConfiguration、@Conditional、@ConditionalOn*、@EnableConfigurationProperties等等。
这一系列注解我觉得大致可分为两类,一类是条件注解,一类是与配置相关的注解,下面分别举一些例子进行说明。
条件注解
@ConditionalOnBean当容器里有指定的bean类或者名称时,满足匹配条件
@ConditionalOnMissingBean当容器里缺少指定的bean类或者名称时,满足匹配条件
@ConditionalOnProperty检查指定的属性是否有特定的值,name为指定值的key,havingValue为指定值,matchIfMissing为缺少或为设置值时,是否也进行匹配
@ConditionOnClass当有指定类在classpath时,满足匹配条件
@ConditionOnMissClass当指定类在classpath不存在时,满足匹配条件
配置相关注解
@EnableAutoConfiguration开启自动配置
@AutoConfigureAfter在指定的自动配置类之后进行配置
@AutoConfigureBefore在指定的自动配置类之前进行配置
@EnableConfigurationProperties开启对
@ConfigurationProperties修饰的bean的支持,将@ConfigurationProperties修饰的类注册成bean
而最核心的我想就是@EnableAutoConfiguration注解了,毕竟只有有了它才能开启自动配置,是所有自动配置的起点,那么就从它开始探索下自动配置的原理。
以下源码版本为springboot 2.0.5.RELEASE
先看下这个注解:
1 | (ElementType.TYPE) |
可以看到这里导入了AutoConfigurationImportSelector,先看下该类核心的selectImports()方法:
1 |
|
可以看出,先获取到所有配置,然后删除重复的配置,然后获取需要排除的配置类,再检查需要排除的配置类,从所有配置中移除需要排除的配置,再使用filter过滤掉不满足自动导入条件的配置(例如使用了@Contional及衍生的条件注解的配置类),最后将剩下的配置类返回。
下面我们具体地看下selectImports()中的getCandidateConfigurations():
1 | protected List<String> getCandidateConfigurations(AnnotationMetadata metadata, |
该方法主要通过SpringFactoriesLoader.loadFactorynames()使用当前的类加载器返回指定EnableAutoConfiguration在META-INF/spring.factories对应的所有配置类名。
那么META-INF/spring.factories是什么呢,在spring-boot-autoconfigure.jar包下有这样一个文件:
1 | # Auto Configure |
可以看到,这里几乎写了所有springboot提供的各种配置类,所以@EnableAutoConfiguration导入了AutoConfigurationImportSelector,就几乎相当于将所有的配置类都引入进来加载了,所以springboot的自动配置换句话说,其实是帮我们定义了很多通用配置的配置类,再统一按条件引入进来加载。
至于selectImports()中其他作用的实现都比较简单,值得一看的是通过filter(configurations, autoConfigurationMetadata)过滤不满足条件的配置类,源码:
1 | private List<String> filter(List<String> configurations, |
这里主要是从META-INF/spring.factories中获取到AutoConfigurationImportFilter:
1 | # Auto Configuration Import Filters |
即OnClassCondition,调用match()方法检查是否存在有@ConditionalOnClass和@ContionalOnMissClass注解的配置类。
至此,关于@EnableAutoConfiguration的自动配置原理我们心里也有了答案。