参考文献

@EnableAutoConfiguration注解

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
@AutoConfigurationPackage
// 入口
@Import(AutoConfigurationImportSelector.class)
public @interface EnableAutoConfiguration {

/**
* Environment property that can be used to override when auto-configuration is
* enabled.
*/
String ENABLED_OVERRIDE_PROPERTY = "spring.boot.enableautoconfiguration";

/**
* Exclude specific auto-configuration classes such that they will never be applied.
* @return the classes to exclude
*/
Class<?>[] exclude() default {};

/**
* Exclude specific auto-configuration class names such that they will never be
* applied.
* @return the class names to exclude
* @since 1.3.0
*/
String[] excludeName() default {};

}

SpringBoot自动装配原理

  • 基于SpringBoot2.7x

  • @EnableAutoConfiguration注解是 Spring Boot 自动装配机制的入口,它会启用 Spring Boot 的自动装配功能.@EnableAutoConfiguration 注解的主要作用是导入自动配置类,而这些自动配置类都包含在spring-boot-autoconfigure.jar包中.

  • @EnableAutoConfiguration 注解通过@Import注解导入了AutoConfigurationImportSelector类,这个类会通过SpringFactoriesLoader.loadFactoryNamesImportCandidates.load(AutoConfiguration.class, getBeanClassLoader()).forEach(configurations::add)扫描classpath下的 META-INF/spring.factories 文件和META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports 文件,读取其中的配置信息,然后根据这些配置信息,将这些类加载到IoC容器中.值得注意的是并不是两个文件中所有的类一定都会被加载,还要结合spring-autoconfigure-metadata.properties来判断某个 Bean 是否需要装配.如果符合条件,则将这个 Bean 自动装配到 IOC 容器中.

    • 具体来说,当 Spring Boot 应用启动时,它会自动扫描classpath下的 META-INF/spring.factories 文件,读取其中的配置信息,并根据配置信息自动装配相应的 Bean。其中,spring.factories 文件中的每个配置项都包含一个 key-value 对,其中 key 是自动配置类的注解全名,value 是自动配置类的全限定类名。
    • org.springframework.boot.autoconfigure.AutoConfiguration.imports的作用就是在这个过程中,指定需要额外导入的配置类。这些额外导入的配置类可以是自动配置类,也可以是普通的配置类。
    • 通过spring-autoconfigure-metadata.properties来过滤

结合SpringBoot启动流程分析@EnableAutoConfiguration流程

入口org.springframework.boot.SpringApplication#run

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
/**
* Run the Spring application, creating and refreshing a new
* {@link ApplicationContext}.
* @param args the application arguments (usually passed from a Java main method)
* @return a running {@link ApplicationContext}
*/
public ConfigurableApplicationContext run(String... args) {
// ...略
try {
ApplicationArguments applicationArguments = new DefaultApplicationArguments(args);
ConfigurableEnvironment environment = prepareEnvironment(listeners, bootstrapContext, applicationArguments);
configureIgnoreBeanInfo(environment);
Banner printedBanner = printBanner(environment);
// 一般web应用,最终会执行 new AnnotationConfigServletWebServerApplicationContext()来创建context
context = createApplicationContext();
context.setApplicationStartup(this.applicationStartup);
prepareContext(bootstrapContext, context, environment, listeners, applicationArguments, printedBanner);
// 入口
refreshContext(context);

afterRefresh(context, applicationArguments);
Duration timeTakenToStartup = Duration.ofNanos(System.nanoTime() - startTime);
if (this.logStartupInfo) {
new StartupInfoLogger(this.mainApplicationClass).logStarted(getApplicationLog(), timeTakenToStartup);
}
listeners.started(context, timeTakenToStartup);
callRunners(context, applicationArguments);
}
catch (Throwable ex) {
handleRunFailure(context, ex, listeners);
throw new IllegalStateException(ex);
}
// ...略
return context;
}

private void refreshContext(ConfigurableApplicationContext context) {
if (this.registerShutdownHook) {
shutdownHook.registerApplicationContext(context);
}
refresh(context);
}

/**
* Refresh the underlying {@link ApplicationContext}.
* @param applicationContext the application context to refresh
*/
protected void refresh(ConfigurableApplicationContext applicationContext) {
// 跳转到父类org.springframework.context.support.AbstractApplicationContext#refresh中
applicationContext.refresh();
}

Spring上下文核心方法org.springframework.context.support.AbstractApplicationContext#refresh

  • 主要看TODO 5
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
@Override
public void refresh() throws BeansException, IllegalStateException {
synchronized (this.startupShutdownMonitor) {
StartupStep contextRefresh = this.applicationStartup.start("spring.context.refresh");

// TODO 1. 初始化前的准备工作,例如对系统属性或者环境变量进行准备及验证
// Prepare this context for refreshing.
prepareRefresh();

// TODO 2. 初始化BeanFactory,并进行XML文件读取
// Tell the subclass to refresh the internal bean factory.
ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();

// TODO 3. 对BeanFactory进行各种功能填充
// Prepare the bean factory for use in this context.
prepareBeanFactory(beanFactory);

try {
// TODO 4. 子类覆盖方法做额外的处理
// Allows post-processing of the bean factory in context subclasses.
postProcessBeanFactory(beanFactory);

StartupStep beanPostProcess = this.applicationStartup.start("spring.context.beans.post-process");

// TODO 5. 激活各种BeanFactoryPostProcessor
// @Configuration和@Import就是在此处处理的
// 具体流程: invokeBeanFactoryPostProcessors
// --> org.springframework.context.support.PostProcessorRegistrationDelegate.invokeBeanFactoryPostProcessors
// 该类硬编码注册的后处理器,其中org.springframework.context.annotation.ConfigurationClassPostProcessor的触发就在该类中触发
// --> org.springframework.context.annotation.ConfigurationClassPostProcessor.processConfigBeanDefinitions
// Invoke factory processors registered as beans in the context.
invokeBeanFactoryPostProcessors(beanFactory);

// TODO 6. 注册拦截Bean创建的Bean处理器,这里只是注册,真正的调用是在getBean时候
// Register bean processors that intercept bean creation.
registerBeanPostProcessors(beanFactory);
beanPostProcess.end();

// TODO 7. 为上下文初始化Message源,即不同语言的消息体,国际化处理
// Initialize message source for this context.
initMessageSource();

// TODO 8. 初始化应用消息广播器,并放入"ApplicationEventMulticaster"bean中
// Initialize event multicaster for this context.
initApplicationEventMulticaster();

// TODO 9. 留给子类来初始化其他的Bean
// Initialize other special beans in specific context subclasses.
onRefresh();

// TODO 10. 在所有注册bean中查找Listener Bean,注册到消息广播中
// Check for listener beans and register them.
registerListeners();

// TODO 11. 初始化剩下的单实例(非惰性的)
// Instantiate all remaining (non-lazy-init) singletons.
finishBeanFactoryInitialization(beanFactory);

// TODO 12. 完成刷新过程,通知生命周期处理器LifecycleProcessor刷新过程,同时发出ContextRefreshEvent通知别人
// Last step: publish corresponding event.
finishRefresh();
}

catch (BeansException ex) {
if (logger.isWarnEnabled()) {
logger.warn("Exception encountered during context initialization - " +
"cancelling refresh attempt: " + ex);
}

// Destroy already created singletons to avoid dangling resources.
destroyBeans();

// Reset 'active' flag.
cancelRefresh(ex);

// Propagate exception to caller.
throw ex;
}

finally {
// Reset common introspection caches in Spring's core, since we
// might not ever need metadata for singleton beans anymore...
resetCommonCaches();
contextRefresh.end();
}
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
/**
* Instantiate and invoke all registered BeanFactoryPostProcessor beans,
* respecting explicit order if given.
* <p>Must be called before singleton instantiation.
*/
protected void invokeBeanFactoryPostProcessors(ConfigurableListableBeanFactory beanFactory) {
// 接下来进入PostProcessorRegistrationDelegate.invokeBeanFactoryPostProcessors方法
PostProcessorRegistrationDelegate.invokeBeanFactoryPostProcessors(beanFactory, getBeanFactoryPostProcessors());

// Detect a LoadTimeWeaver and prepare for weaving, if found in the meantime
// (e.g. through an @Bean method registered by ConfigurationClassPostProcessor)
if (!NativeDetector.inNativeImage() && beanFactory.getTempClassLoader() == null && beanFactory.containsBean(LOAD_TIME_WEAVER_BEAN_NAME)) {
beanFactory.addBeanPostProcessor(new LoadTimeWeaverAwareProcessor(beanFactory));
beanFactory.setTempClassLoader(new ContextTypeMatchClassLoader(beanFactory.getBeanClassLoader()));
}
}
  • PostProcessorRegistrationDelegate.invokeBeanFactoryPostProcessors方法较长此处不展示,该方法会调用org.springframework.context.support.PostProcessorRegistrationDelegate#invokeBeanDefinitionRegistryPostProcessors来遍历执行postProcessorpostProcessBeanDefinitionRegistry方法.其中负责@Import注解的postProcessororg.springframework.context.annotation.ConfigurationClassPostProcessor

org.springframework.context.annotation.ConfigurationClassPostProcessor

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
/**
* Derive further bean definitions from the configuration classes in the registry.
*/
@Override
public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) {
int registryId = System.identityHashCode(registry);
if (this.registriesPostProcessed.contains(registryId)) {
throw new IllegalStateException(
"postProcessBeanDefinitionRegistry already called on this post-processor against " + registry);
}
if (this.factoriesPostProcessed.contains(registryId)) {
throw new IllegalStateException(
"postProcessBeanFactory already called on this post-processor against " + registry);
}
this.registriesPostProcessed.add(registryId);

processConfigBeanDefinitions(registry);
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
/**
* Build and validate a configuration model based on the registry of
* {@link Configuration} classes.
*/
public void processConfigBeanDefinitions(BeanDefinitionRegistry registry) {
// ...略
// Parse each @Configuration class
ConfigurationClassParser parser = new ConfigurationClassParser(
this.metadataReaderFactory, this.problemReporter, this.environment,
this.resourceLoader, this.componentScanBeanNameGenerator, registry);
do {
StartupStep processConfig = this.applicationStartup.start("spring.context.config-classes.parse");
// 进行解析
parser.parse(candidates);

// ...略
}
while (!candidates.isEmpty());
// ...略
}

org.springframework.context.annotation.ConfigurationClassParser

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
public void parse(Set<BeanDefinitionHolder> configCandidates) {
for (BeanDefinitionHolder holder : configCandidates) {
BeanDefinition bd = holder.getBeanDefinition();
try {
if (bd instanceof AnnotatedBeanDefinition) {
// 先解析扫描bean, 在此方法中向deferredImportSelectorHandler中添加了一个对象, 存储了可延迟导入的selector列表
parse(((AnnotatedBeanDefinition) bd).getMetadata(), holder.getBeanName());
}
else if (bd instanceof AbstractBeanDefinition && ((AbstractBeanDefinition) bd).hasBeanClass()) {
parse(((AbstractBeanDefinition) bd).getBeanClass(), holder.getBeanName());
}
else {
parse(bd.getBeanClassName(), holder.getBeanName());
}
}
catch (BeanDefinitionStoreException ex) {
throw ex;
}
catch (Throwable ex) {
throw new BeanDefinitionStoreException(
"Failed to parse configuration class [" + bd.getBeanClassName() + "]", ex);
}
}
// 执行对象的process方法
this.deferredImportSelectorHandler.process();
}
  • 进入解析方法最终会进入org.springframework.context.annotation.ConfigurationClassParser#doProcessConfigurationClass方法
    • 该方法处理各种注解,如@Component,@PropertySource,@ComponentScan,@Import
1
2
3
4
5
6
7
8
9
10
11
12
13
@Nullable
protected final SourceClass doProcessConfigurationClass(
ConfigurationClass configClass, SourceClass sourceClass, Predicate<String> filter)
throws IOException {
// ...略

// Process any @Import annotations
processImports(configClass, sourceClass, getImports(sourceClass), filter, true);
// ...略

// No superclass -> processing is complete
return null;
}

@Import核心处理方法

  • 注意点: 因为AutoConfigurationImportSelector实现了DeferredImportSelector接口,因此不会直接执行selectImports方法.
    • DeferredImportSelector接口用于支持延迟导入配置类的功能.
    • 在 Spring Framework 中,@Import 注解用于导入其他配置类或者导入其他 Spring 配置。使用 @Import 注解可以将其他类引入到当前的配置类中,这样就可以在当前配置类中使用被引入的类中的 Bean 了。但是,如果被引入的配置类中存在某些依赖还没有初始化完成,就会导致引入的 Bean 无法正常使用。
    • 为了解决这个问题,Spring Framework 提供了 DeferredImportSelector 接口,用于支持延迟导入配置类的功能。DeferredImportSelector 接口继承自 ImportSelector 接口,可以返回一个 DeferredImportSelector.Group 对象,用于延迟加载配置类并解析其中的 BeanDefinition。
    • 具体来说,DeferredImportSelector.Group 接口有两个方法:
      • getImports() 方法:用于返回需要导入的配置类的全限定类名。
      • process() 方法:用于在应用程序上下文启动后处理被导入的配置类。
    • 通过实现 DeferredImportSelector 接口和 DeferredImportSelector.Group 接口,可以实现在应用程序上下文启动前或启动后,动态加载配置类中的 BeanDefinition,从而可以解决 Bean 初始化的依赖问题。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
private void processImports(ConfigurationClass configClass, SourceClass currentSourceClass,
Collection<SourceClass> importCandidates, Predicate<String> exclusionFilter,
boolean checkForCircularImports) {

if (importCandidates.isEmpty()) {
return;
}

if (checkForCircularImports && isChainedImportOnStack(configClass)) {
this.problemReporter.error(new CircularImportProblem(configClass, this.importStack));
}
else {
this.importStack.push(configClass);
try {
for (SourceClass candidate : importCandidates) {
if (candidate.isAssignable(ImportSelector.class)) {
// Candidate class is an ImportSelector -> delegate to it to determine imports
Class<?> candidateClass = candidate.loadClass();
ImportSelector selector = ParserStrategyUtils.instantiateClass(candidateClass, ImportSelector.class,
this.environment, this.resourceLoader, this.registry);
Predicate<String> selectorFilter = selector.getExclusionFilter();
if (selectorFilter != null) {
exclusionFilter = exclusionFilter.or(selectorFilter);
}
// 如果实现了接口DeferredImportSelector 则添加到名为deferredImportSelectors的list中暂存
if (selector instanceof DeferredImportSelector) {
this.deferredImportSelectorHandler.handle(configClass, (DeferredImportSelector) selector);
}
else {
// 否则执行selectImports方法
String[] importClassNames = selector.selectImports(currentSourceClass.getMetadata());
Collection<SourceClass> importSourceClasses = asSourceClasses(importClassNames, exclusionFilter);
processImports(configClass, currentSourceClass, importSourceClasses, exclusionFilter, false);
}
}
else if (candidate.isAssignable(ImportBeanDefinitionRegistrar.class)) {
// Candidate class is an ImportBeanDefinitionRegistrar ->
// delegate to it to register additional bean definitions
Class<?> candidateClass = candidate.loadClass();
ImportBeanDefinitionRegistrar registrar =
ParserStrategyUtils.instantiateClass(candidateClass, ImportBeanDefinitionRegistrar.class,
this.environment, this.resourceLoader, this.registry);
configClass.addImportBeanDefinitionRegistrar(registrar, currentSourceClass.getMetadata());
}
else {
// Candidate class not an ImportSelector or ImportBeanDefinitionRegistrar ->
// process it as an @Configuration class
this.importStack.registerImport(
currentSourceClass.getMetadata(), candidate.getMetadata().getClassName());
processConfigurationClass(candidate.asConfigClass(configClass), exclusionFilter);
}
}
}
catch (BeanDefinitionStoreException ex) {
throw ex;
}
catch (Throwable ex) {
throw new BeanDefinitionStoreException(
"Failed to process import candidates for configuration class [" +
configClass.getMetadata().getClassName() + "]", ex);
}
finally {
this.importStack.pop();
}
}
}
  • 解析完成后执行 this.deferredImportSelectorHandler.process();
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
public void process() {
List<DeferredImportSelectorHolder> deferredImports = this.deferredImportSelectors;
this.deferredImportSelectors = null;
try {
if (deferredImports != null) {
DeferredImportSelectorGroupingHandler handler = new DeferredImportSelectorGroupingHandler();
// 排序 按照优先级、sort大小排序
deferredImports.sort(DEFERRED_IMPORT_COMPARATOR);
// 调用org.springframework.context.annotation.ConfigurationClassParser.DeferredImportSelectorGroupingHandler.register
deferredImports.forEach(handler::register);
handler.processGroupImports();
}
}
finally {
this.deferredImportSelectors = new ArrayList<>();
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
public void register(DeferredImportSelectorHolder deferredImport) {
// 调用org.springframework.boot.autoconfigure.AutoConfigurationImportSelector.getImportGroup
// 返回AutoConfigurationGroup.class
Class<? extends Group> group = deferredImport.getImportSelector().getImportGroup();
// 创建Group对象, 用DeferredImportSelectorGrouping包装并存入到map中
DeferredImportSelectorGrouping grouping = this.groupings.computeIfAbsent(
(group != null ? group : deferredImport),
key -> new DeferredImportSelectorGrouping(createGroup(group)));
// 向deferredImports对象添加元素, 后面会使用
grouping.add(deferredImport);
// 存入map中 key为启动类的元数据 value是启动类
this.configurationClasses.put(deferredImport.getConfigurationClass().getMetadata(),
deferredImport.getConfigurationClass());
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
public void processGroupImports() {
// 只有一个元素, register方法放入的
for (DeferredImportSelectorGrouping grouping : this.groupings.values()) {
Predicate<String> exclusionFilter = grouping.getCandidateFilter();
grouping.getImports().forEach(entry -> {
// 获取主配置类 启动类
ConfigurationClass configurationClass = this.configurationClasses.get(entry.getMetadata());
try {
// 逐个执行导入 至此执行完成后, 扫描出的类都会注册到BeanDefinition中 等待Spring容器对对象实例化和初始化
processImports(configurationClass, asSourceClass(configurationClass, exclusionFilter),
Collections.singleton(asSourceClass(entry.getImportClassName(), exclusionFilter)),
exclusionFilter, false);
}
catch (BeanDefinitionStoreException ex) {
throw ex;
}
catch (Throwable ex) {
throw new BeanDefinitionStoreException(
"Failed to process import candidates for configuration class [" +
configurationClass.getMetadata().getClassName() + "]", ex);
}
});
}
}
1
2
3
4
5
6
7
8
9
10
public Iterable<Group.Entry> getImports() {
// 前面放入的一个元素 此处循环
for (DeferredImportSelectorHolder deferredImport : this.deferredImports) {
// group为AutoConfigurationGroup对象
// 执行org.springframework.boot.autoconfigure.AutoConfigurationImportSelector.AutoConfigurationGroup.process方法
this.group.process(deferredImport.getConfigurationClass().getMetadata(),
deferredImport.getImportSelector());
}
return this.group.selectImports();
}

org.springframework.boot.autoconfigure.AutoConfigurationImportSelector.AutoConfigurationGroup

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
@Override
public void process(AnnotationMetadata annotationMetadata, DeferredImportSelector deferredImportSelector) {
Assert.state(deferredImportSelector instanceof AutoConfigurationImportSelector,
() -> String.format("Only %s implementations are supported, got %s",
AutoConfigurationImportSelector.class.getSimpleName(),
deferredImportSelector.getClass().getName()));
// 调用getAutoConfigurationEntry检索spring.factories文件, 存储并排除文件中配置的bean
AutoConfigurationEntry autoConfigurationEntry = ((AutoConfigurationImportSelector) deferredImportSelector)
.getAutoConfigurationEntry(annotationMetadata);
this.autoConfigurationEntries.add(autoConfigurationEntry);
for (String importClassName : autoConfigurationEntry.getConfigurations()) {
// 将过滤后的类存入到entries map中
this.entries.putIfAbsent(importClassName, annotationMetadata);
}
}

AutoConfigurationImportSelector

  1. 通过SpringFactoriesLoader#loadFactoryName(Class,ClassLoader)方法读取所有META-INF/spring.factories资源中@EnableAutoConfiguration所关联的自动装配Class集合
  2. 读取当前配置类所标注的@EnableAutoConfiguration属性excludeexcludeName,并与spring.autoconfigure.exclude配置属性合并为自动装配Class排除集合
  3. 检查自动装配排除结核是否合法
  4. 排除候选自动装配Class集合中的排除名单
  5. 再次过滤候选自动装配Class集合中Class不存在的成员
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
public class AutoConfigurationImportSelector implements DeferredImportSelector, BeanClassLoaderAware,
ResourceLoaderAware, BeanFactoryAware, EnvironmentAware, Ordered {
// ...略

@Override
public String[] selectImports(AnnotationMetadata annotationMetadata) {
if (!isEnabled(annotationMetadata)) {
return NO_IMPORTS;
}

AutoConfigurationEntry autoConfigurationEntry =
getAutoConfigurationEntry(annotationMetadata);
return StringUtils.toStringArray(autoConfigurationEntry.getConfigurations());
}

/**
* Return the {@link AutoConfigurationEntry} based on the {@link AnnotationMetadata}
* of the importing {@link Configuration @Configuration} class.
* @param annotationMetadata the annotation metadata of the configuration class
* @return the auto-configurations that should be imported
*/
protected AutoConfigurationEntry getAutoConfigurationEntry(AnnotationMetadata annotationMetadata) {
if (!isEnabled(annotationMetadata)) {
return EMPTY_ENTRY;
}
// 获取EnableAutoConfiguration注解的属性
AnnotationAttributes attributes = getAttributes(annotationMetadata);
// 扫描各个包下META-INF/spring.factories文件中配置EnableAutoConfiguration 大约100+
List<String> configurations = getCandidateConfigurations(annotationMetadata, attributes);
configurations = removeDuplicates(configurations);
// 获取注解上排除的类 @SpringBootApplication(exclude= {DataSourceAutoConfiguration.class})
Set<String> exclusions = getExclusions(annotationMetadata, attributes);
checkExcludedClasses(configurations, exclusions);
// 去掉排除的类
configurations.removeAll(exclusions);
// 使用filter过滤 过滤不存在的类(尝试加载 异常说明不存在)
configurations = getConfigurationClassFilter().filter(configurations);
// 发送一个AutoConfigurationImportEvent事件通知
fireAutoConfigurationImportEvents(configurations, exclusions);
return new AutoConfigurationEntry(configurations, exclusions);
}

/**
* Return the auto-configuration class names that should be considered. By default
* this method will load candidates using {@link ImportCandidates} with
* {@link #getSpringFactoriesLoaderFactoryClass()}. For backward compatible reasons it
* will also consider {@link SpringFactoriesLoader} with
* {@link #getSpringFactoriesLoaderFactoryClass()}.
* @param metadata the source metadata
* @param attributes the {@link #getAttributes(AnnotationMetadata) annotation
* attributes}
* @return a list of candidate configurations
*/
protected List<String> getCandidateConfigurations(AnnotationMetadata metadata, AnnotationAttributes attributes) {
List<String> configurations = new ArrayList<>(
// 核心
SpringFactoriesLoader.loadFactoryNames(getSpringFactoriesLoaderFactoryClass(), getBeanClassLoader()));
ImportCandidates.load(AutoConfiguration.class, getBeanClassLoader()).forEach(configurations::add);
Assert.notEmpty(configurations,
"No auto configuration classes found in META-INF/spring.factories nor in META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports. If you "
+ "are using a custom packaging, make sure that file is correct.");
return configurations;
}
// ...略
}

org.springframework.core.io.support.SpringFactoriesLoader

  • 加载META-INF/spring.factories文件
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
public final class SpringFactoriesLoader {
/**
* The location to look for factories.
* <p>Can be present in multiple JAR files.
*/
public static final String FACTORIES_RESOURCE_LOCATION = "META-INF/spring.factories";


// ...略
/**
* Load the fully qualified class names of factory implementations of the
* given type from {@value #FACTORIES_RESOURCE_LOCATION}, using the given
* class loader.
* <p>As of Spring Framework 5.3, if a particular implementation class name
* is discovered more than once for the given factory type, duplicates will
* be ignored.
* @param factoryType the interface or abstract class representing the factory
* @param classLoader the ClassLoader to use for loading resources; can be
* {@code null} to use the default
* @throws IllegalArgumentException if an error occurs while loading factory names
* @see #loadFactories
*/
public static List<String> loadFactoryNames(Class<?> factoryType, @Nullable ClassLoader classLoader) {
ClassLoader classLoaderToUse = classLoader;
if (classLoaderToUse == null) {
classLoaderToUse = SpringFactoriesLoader.class.getClassLoader();
}
String factoryTypeName = factoryType.getName();
return loadSpringFactories(classLoaderToUse).getOrDefault(factoryTypeName, Collections.emptyList());
}

private static Map<String, List<String>> loadSpringFactories(ClassLoader classLoader) {
Map<String, List<String>> result = cache.get(classLoader);
if (result != null) {
return result;
}

result = new HashMap<>();
try {
// 加载META-INF/spring.factories文件
Enumeration<URL> urls = classLoader.getResources(FACTORIES_RESOURCE_LOCATION);
while (urls.hasMoreElements()) {
URL url = urls.nextElement();
UrlResource resource = new UrlResource(url);
Properties properties = PropertiesLoaderUtils.loadProperties(resource);
for (Map.Entry<?, ?> entry : properties.entrySet()) {
String factoryTypeName = ((String) entry.getKey()).trim();
String[] factoryImplementationNames =
StringUtils.commaDelimitedListToStringArray((String) entry.getValue());
for (String factoryImplementationName : factoryImplementationNames) {
result.computeIfAbsent(factoryTypeName, key -> new ArrayList<>())
.add(factoryImplementationName.trim());
}
}
}

// Replace all lists with unmodifiable lists containing unique elements
result.replaceAll((factoryType, implementations) -> implementations.stream().distinct()
.collect(Collectors.collectingAndThen(Collectors.toList(), Collections::unmodifiableList)));
cache.put(classLoader, result);
}
catch (IOException ex) {
throw new IllegalArgumentException("Unable to load factories from location [" +
FACTORIES_RESOURCE_LOCATION + "]", ex);
}
return result;
}


// ...略
}

org.springframework.boot.context.annotation.ImportCandidates

  • 加载org.springframework.boot.autoconfigure.AutoConfiguration.imports文件
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
/**
* Loads the names of import candidates from the classpath.
*
* The names of the import candidates are stored in files named
* {@code META-INF/spring/full-qualified-annotation-name.imports} on the classpath.
* Every line contains the full qualified name of the candidate class. Comments are
* supported using the # character.
* @param annotation annotation to load
* @param classLoader class loader to use for loading
* @return list of names of annotated classes
*/
public static ImportCandidates load(Class<?> annotation, ClassLoader classLoader) {
Assert.notNull(annotation, "'annotation' must not be null");
ClassLoader classLoaderToUse = decideClassloader(classLoader);
String location = String.format(LOCATION, annotation.getName());
Enumeration<URL> urls = findUrlsInClasspath(classLoaderToUse, location);
List<String> autoConfigurations = new ArrayList<>();
while (urls.hasMoreElements()) {
URL url = urls.nextElement();
autoConfigurations.addAll(readAutoConfigurations(url));
}
return new ImportCandidates(autoConfigurations);
}

@EnableAutoConfiguration排序自动装配组件

  • 绝对自动装配顺序-- @AutoConfigureOrder
  • 相对自动装配顺序-- @AutoConfigureBefore@AutoConfigureAfter