在SpringBoot中,不得不说的一个点就是自动装配,它是starter的基础,也是SpringBoot的核心,那么什么是自动装配呢?showTime
自动装配在SpringBoot中是通过@EnableAutoConfiguration的注解来实现的,而这个注解的声明是在复合注解 @SpringBootApplication中

开始正餐之前先给大家说下其他注解
@SpringBootConfiguration 是一个声明当前类是boot启动类,是一个复合注解
@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Configuration
public @interface SpringBootConfiguration {
@AliasFor(
annotation = Configuration.class
)
boolean proxyBeanMethods() default true;
}正餐开始 @EnableAutoConfiguration,跟踪源码点进去如下

当大家看到@AutoConfigurationPackage这个注解的时候是不是就豁然开朗,这就是为什么Spring扫描启动类当前所在包及子包下的所有组件
大家如果经常阅读源码的话会看见@import和@Conditional这两个注解,本节遇到了@import这个注解,我就先说明这个注解的作用:导入类。
@Import({AutoConfigurationImportSelector.class})
大家注解@import它导入的这个配置类是一个叫 AutoConfigurationImportSelector 这个一个配置类,当然就目前而言,不管这个类是做什么的,大家一定得清楚就是它一定会实现配置类的导入,至于具体导入的方式和@Configuration有什么区别,就是下面我要说明的
AutoConfigurationImportSelector这个类最终实现了ImportSelector,ImportSelector是一个接口,里面有一个抽象方法,返回的是一个String数组,在这个数组中可以指定需要装配到IOC容器的类,当在@Import中导入它的实现类侯,就会把该类中返回的Class名称都装载到IOC容器中



基于前面的分析,大家可以猜想到,自动装配的核心是扫描约定目录下的文件进行解析,解析后将得到的Configuration配置类通过ImportSelector进行导入,完成Bean的自动装配。那么我们下面仔细分析下AutoConfigurationImportSelector中的selectImport方法
AutoConfigurationImportSelector主要有两个功能:
1.从META-INF/spring-autoconfigure-metadata.properties中加载自动装配的条件元数据,简单来说就是只有满足条件的Bean才能够进行装配
2.收集所有符合条件的配置类 antoConfigurationEntry.getConfiguration(),完成装配


马上就是核心加载过程了:看我的标记,下面介绍此方法
public String[] selectImports(AnnotationMetadata annotationMetadata) {
if (!this.isEnabled(annotationMetadata)) {
return NO_IMPORTS;
} else {
AutoConfigurationMetadata autoConfigurationMetadata = AutoConfigurationMetadataLoader.loadMetadata(this.beanClassLoader);
最最核心过程
AutoConfigurationImportSelector.AutoConfigurationEntry autoConfigurationEntry = this.getAutoConfigurationEntry(autoConfigurationMetadata, annotationMetadata);
return StringUtils.toStringArray(autoConfigurationEntry.getConfigurations());
}
}
当你看到这,其实你已经了解了大半,就剩下最后一个Boss需要你KO
----------------------------------------------------------------------------------------------------------------------------------------------------------------
protected AutoConfigurationImportSelector.AutoConfigurationEntry getAutoConfigurationEntry(AutoConfigurationMetadata autoConfigurationMetadata, AnnotationMetadata annotationMetadata) {
if (!this.isEnabled(annotationMetadata)) {
return EMPTY_ENTRY;
} else {
//获得@EnableAutoConfiguration注解中的属性exclude excludeName等
AnnotationAttributes attributes = this.getAttributes(annotationMetadata);
List<String> configurations =
//获得所有自动装配的配置类
this.getCandidateConfigurations(annotationMetadata, attributes);
//去除重复的配置项
configurations = this.removeDuplicates(configurations);
//根据@EnableAutoConfiguration注解中配置的exclude等属性,把不需要的自动装配的类去除
Set<String> exclusions = this.getExclusions(annotationMetadata, attributes);
this.checkExcludedClasses(configurations, exclusions);
configurations.removeAll(exclusions);
configurations = this.filter(configurations, autoConfigurationMetadata);
//广播事件
this.fireAutoConfigurationImportEvents(configurations, exclusions);
return new AutoConfigurationImportSelector.AutoConfigurationEntry(configurations, exclusions);
}
}
总结:就是它获取所有的配置类,通过去重、exclude排除等操作,得到最终需要实现自动装配的配置类。这里需要关注的就是getCandidateConfigurations 他是配置类 最核心 最核心 最核心 最核心
我说了4遍哦,的方法
protected List<String> getCandidateConfigurations(AnnotationMetadata metadata, AnnotationAttributes attributes) {
List<String> configurations = SpringFactoriesLoader.loadFactoryNames(this.getSpringFactoriesLoaderFactoryClass(), this.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;
}这里面用到了SpringFactoriesLoader,它是Spring内部提供的一种加载方式,就跟SPI 一样,(SPI不懂的大家百度下,jdk spi dubbox spi)。简单来说就是扫描classpath下的META-INF/spring.factories文件,其中spring.factories文件中的数据以key=value格式存储,而这个加载器会根据key到到对应的value.

















