本文基于SpringBoot 2.5.7版本进行讲解
在上一篇文章,SpringBoot自动配置之@SpringBootApplication注解 - SpringBoot自动配置(一)说到,SpringBoot自动配置的核心就在@EnableAutoConfiguration
注解上,这个注解通过@Import(AutoConfigurationImportSelector)
来完成自动配置。
所以说,SpringBoot自动配置的奥秘就隐藏在AutoConfigurationImportSelector
类中。
阅读须知
在分析AutoConfigurationImportSelector如何实现SpringBoot自动配置之前,读者需要了解:
@Import
注解是什么?有什么用?- ImportSelector接口是什么?有什么用?
AutoConfigurationImportSelector类
了解一个类,我们首先就要先看这个类的定义:
1 | java复制代码public class AutoConfigurationImportSelector implements DeferredImportSelector, BeanClassLoaderAware, |
我们可以看到它实现了DeferredImportSelector
接口,那么接下来再来看看DeferredImportSelector
接口的定义:
1 | java复制代码public interface DeferredImportSelector extends ImportSelector { |
可以看到,DeferredImportSelector
接口又继承了ImportSelector
接口。这样,我们就明白了,AutoConfigurationImportSelector
类必定实现了selectImports()
方法,这个方法应该就是SpringBoot能够实现自动配置的核心。
selectImports()方法
1 | java复制代码private static final String[] NO_IMPORTS = {}; |
selectImports()方法的源码没有多少。
isEnabled()方法判断SpringBoot是否开启了自动配置。若开启就通过getAutoConfigurationEntry()来获取需要配置的Bean全限定名数组,否则就直接返回空数组。
isEnabled():判断SpringBoot是否开启自动配置
1 | java复制代码protected boolean isEnabled(AnnotationMetadata metadata) { |
EnableAutoConfiguration.ENABLED_OVERRIDE_PROPERTY
是什么?我们看下它的定义:
1 | java复制代码String ENABLED_OVERRIDE_PROPERTY = "spring.boot.enableautoconfiguration"; |
看到这里,我们可以猜到这就是在配置文件application.yml或者application.properties中的配置。因此,我们可以在配置文件中来决定SpringBoot是否开启自动配置。
当我们没有配置的时候,默认就是开启自动配置的。
getAutoConfigurationEntry()方法:获取需要自动配置的bean信息
话不多说,先上源码:
1 | java复制代码protected AutoConfigurationEntry getAutoConfigurationEntry(AnnotationMetadata annotationMetadata) { |
在这里,我们只需要知道这个getAutoConfigurationEntry()
方法是用来获取需要自动配置的bean信息,以及里面每个方法做了什么,有个大概的印象就可以了。
下面会对每个方法作更近一步的讲解。
getAttributes():获取@EnableAutoConfiguration注解属性
1 | java复制代码protected AnnotationAttributes getAttributes(AnnotationMetadata metadata) { |
看了上面断点的图,我们大概就明白了,这个方法就是获取@EnableAutoConfiguration
注解的属性。
getCandidateConfigurations():从spring.factories文件获取需要配置的bean
1 | java复制代码protected List<String> getCandidateConfigurations(AnnotationMetadata metadata, AnnotationAttributes attributes) { |
getCandidateConfigurations()
方法通过SpringFactoriesLoader
的loadFactoryNames()
方法从所有的spring.factories文件中获取需要配置的bean全限定名列表。
这里,对于SpringFactoriesLoader
类的loadFactoryNames()
方法就不展开讲了。有兴趣的可以自己阅读下源码。
到了这里,可能有很多人都疑惑了。spring.factories文件是什么?它又在哪里?
spring.factories文件本质上与properties文件相似,其中包含一组或多组键值对。其中,key的取值是接口的全限定名,value的取值是接口实现类的全限定名。一个接口可以设置多个实现类,不同实现类之间使用,
隔开。例如:
1 | ini复制代码org.springframework.boot.autoconfigure.EnableAutoConfiguration=\ |
SpringFactoriesLoader
会扫描所有jar包类路径下的META-INF/spring.factories文件,并获取指定接口的配置。
这里提一句,getCandidateConfigurations()
方法获取的是EnableAutoConfiguration
接口的配置。
removeDuplicates():去重
1 | java复制代码protected final <T> List<T> removeDuplicates(List<T> list) { |
我们知道SpringFactoriesLoader
的loadFactoryNames()
方法会从所有jar包类路径下的META-INF/spring.factories读取配置。就是说会从不同的spring.factories文件中读取配置,那么就有可能会出现配置了相同的类,这里就是对这些数据进行去重。
getExclusions():获取注解的exclude和excludeName属性配置的需要排除的类全限定名集合
1 | java复制代码protected Set<String> getExclusions(AnnotationMetadata metadata, AnnotationAttributes attributes) { |
getExclusions
方法就是将上面getAttributes()
方法获取到@EnableAutoConfiguration
注解的exclude和excludeName属性的值加入到excluded集合中。
checkExcludedClasses():检查排除类
1 | java复制代码private void checkExcludedClasses(List<String> configurations, Set<String> exclusions) { |
检查被排除的类是否可以实例化以及自动配置类列表是否包含该类。如果存在无效排除类,那么就抛出异常。
getConfigurationClassFilter():获取配置类过滤器
1 | java复制代码private ConfigurationClassFilter getConfigurationClassFilter() { |
getConfigurationClassFilter()
方法通过getAutoConfigurationImportFilters()
方法获取到spring.factories文件中AutoConfigurationImportFilter
接口的配置,然后将其封装到ConfigurationClassFilter
对象中。
总结
上面,我们介绍了AutoConfigurationImportSelector
类是ImportSelector
的实现类,实现了selectImports()
方法。selectImports()
方法又调用getAutoConfigurationEntry()
方法从spring.factories文件中读取配置类的全限定名列表,并进行过滤,最终得到需要自动配置的类全限定名列表。
本文转载自: 掘金