@AutoConfigurationPackage:
@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
@Import({Registrar.class})
@Import 为spring的注解,用来导入配置类或者一些需要前置加载的类,通过进一步点击查看源代码,可以看到Registrar.class实现了ImportBeanDefinitionRegistrar接口,通过@Import 导入该接口的实现类会执行重写的registerBeanDefinitions(AnnotationMetadata metadata, BeanDefinitionRegistry registry)方法。
static class Registrar implements ImportBeanDefinitionRegistrar, DeterminableImports {
Registrar() {
}
public void registerBeanDefinitions(AnnotationMetadata metadata, BeanDefinitionRegistry registry) {
AutoConfigurationPackages.register(registry, (String[])(new AutoConfigurationPackages.PackageImports(metadata)).getPackageNames().toArray(new String[0]));
}
public Set<Object> determineImports(AnnotationMetadata metadata) {
return Collections.singleton(new AutoConfigurationPackages.PackageImports(metadata));
}
}
通过断点测试,我们可以发现(String[])(new AutoConfigurationPackages.PackageImports(metadata)).getPackageNames().toArray(new String[0])的结果是当前启动类所在的包名。而AutoConfigurationPackages.register(BeanDefinitionRegistry registry, String... packageNames)方法的作用是将启动类所在包名/路径名加入容器中,一个专门记录packageNames的集合里。容器会扫描该集合下的路径名,从而去导入相应的组件。
即,@AutoConfigurationPackage 就是将主配置类(@SpringBootApplication 标注的类)所在的包下面所有的组件都扫描注冊到 spring 容器中。
@Import({AutoConfigurationImportSelector.class}):
@Import 注解导入的该类,实现了DeferredImportSelector接口,而DeferredImportSelector又实现了ImportSelector接口,因此该类实现了ImportSelector接口。通过@Import导入的该接口的实现类会执行重写的selectImports(AnnotationMetadata annotationMetadata)方法,该方法的返回值是String[]类型,即需要自动配置/导入Spring容器中的类的全限定名。
public String[] selectImports(AnnotationMetadata annotationMetadata) {
if (!this.isEnabled(annotationMetadata)) {
return NO_IMPORTS;
} else {
AutoConfigurationImportSelector.AutoConfigurationEntry autoConfigurationEntry = this.getAutoConfigurationEntry(annotationMetadata);
return StringUtils.toStringArray(autoConfigurationEntry.getConfigurations());
}
}
NO_IMPORTS是new String[0],因此我们关注else部分,而else部分只有两条语句,重点在第一条语句对于getAutoConfigurationEntry(AnnotationMetadata annotationMetadata)的调用。
protected AutoConfigurationImportSelector.AutoConfigurationEntry getAutoConfigurationEntry(AnnotationMetadata annotationMetadata) {
if (!this.isEnabled(annotationMetadata)) {
return EMPTY_ENTRY;
} else {
AnnotationAttributes attributes = this.getAttributes(annotationMetadata);
List<String> configurations = this.getCandidateConfigurations(annotationMetadata, attributes);
configurations = this.removeDuplicates(configurations);
Set<String> exclusions = this.getExclusions(annotationMetadata, attributes);
this.checkExcludedClasses(configurations, exclusions);
configurations.removeAll(exclusions);
configurations = this.getConfigurationClassFilter().filter(configurations);
this.fireAutoConfigurationImportEvents(configurations, exclusions);
return new AutoConfigurationImportSelector.AutoConfigurationEntry(configurations, exclusions);
}
这里点进去getCandidateConfigurations(annotationMetadata, annotationAttributes)方法,可以看到方法体中调用另外一个方法loadFactoryNames(factoryType, classLoader),其中factoryType的值为EnableAutoConfiguration,classLoader的值为AppClassLoader(打断点可以观察到)。

loadFactoryNames(factoryType, classLoader)最终返回另外一个方法调用的筛选结果,即loadSpringFactories(classLoader),点进去该方法的源码,在该位置打断点进行观察:

可以看到返回值result的结果是一个key-value保存的Map,展开如下。其中就有我们需要并且由loadFactoryNames(factoryType, classLoader)方法返回的EnableAutoConfiguration部分。loadSpringFactories(classLoader)遍历了所有jar包路径下的META-INF/spring.factories文件,这些文件给Spring中的容器组件进行了相关的设置,并汇总成为一个Map集合,最后返回。

从内往外推的顺序如下:
-
loadSpringFactories()方法加载所有jar包下的META-INF/spring.factories文件中的配置,并将其整理为Map,传递出去;
-
loadFactoryNames()接收到loadSpringFactories()的调用结果,挑选出key为EnableAutoConfiguration的部分,即需要自动配置的部分,将其返回;
-
getAutoConfigurationEntry()获得META-INF/spring.factories需要自动配置的部分,在根据@OnXXXCondition注解筛选排除部分不生效的自动配置,将其返回给selectImports()方法;
-
点进去Map中的EnableAutoConfiguration,可以看到如下全为"xxxxAutoConfiguration"格式的字符串,这就是selectImports()方法返回的需要添加到Spring容器中管理的组件的全限定类名,作用类似于使用@Import引入了@Configuration注解的类,通过这种方式实现自动配置。
