在传统的Spring应用中,开发者需要手动配置大量数据,这种配置通常包括数据源、事务管理、视图解析器等。这种手动配置方式在大型项目中显得特别繁琐且容易出错。

Spring Boot引入自动配置机制,只需要添加相关依赖,无需配置。这极大地简化了Spring应用的配置, 大幅减少了开发者的工作量,帮助开发者快速创建应用。

SpringBoot的自动配置是通过@EnableAutoConfigurationMETA-INF/spring.factories文件实现的,而这些机制的底层依赖于ConfigurationClassPostProcessor来解析和注册自动配置类。

本文会先介绍一些重要概念,然后进入SpringApplication.run 源码逐一串联起这些重要概念,以此来探讨SpringBoot自动配置机制 的实现原理。

分析基于SpringBoot 2.3.4

1. @EnableAutoConfiguration

是一个组合注解,@EnableAutoConfiguration是组合注解@SpringBootApplication 其中的一个注解, 其作用是启用自动配置机制

1
2
3
4
5
6
7
8
9
@Target(ElementType.TYPE)  
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
@SpringBootConfiguration
@EnableAutoConfiguration
@ComponentScan(excludeFilters = { @Filter(type = FilterType.CUSTOM, classes = TypeExcludeFilter.class),
@Filter(type = FilterType.CUSTOM, classes = AutoConfigurationExcludeFilter.class) })
public @interface SpringBootApplication {}

Spring框架提供的各种名字为@Enable开头的Annotat​ion,比如@EnableSchedul​ing、@EnableCaching、@EnableMBeanExport等,@EnableAutoConf​igurat​ion的理念和“做事方式”其实一脉相承,简单概括一下就是,它们的工作方式都是借助@Import的支持,收集和注册特定场景相关的bean定义:

  1. @Enable Schedul​ing是通过@Import将Spring调度框架相关的bean定义都加载到IoC容器。
  2. @Enable M Bean Export是通过@Import将JMX相关的bean定义加载到IoC容器。

@EnableAutoConf​igurat​ion 一样,也是借助@Import的帮助,将所有符合自动配置条件的bean定义加载到IoC容器,仅此而已!

@EnableAutoConfiguration本身也是由多个注解组成

1
2
3
4
5
6
7
8
9
10
11
12
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
@AutoConfigurationPackage
@Import(AutoConfigurationImportSelector.class)
public @interface EnableAutoConfiguration {

Class<?>[] exclude() default {};

String[] excludeName() default {};
}

  • 自动配置包扫描@AutoConfigurationPackage注解标记了包路径,这意味着Spring Boot会自动扫描该包及其子包中的所有组件。
  • 导入选择器@Import(AutoConfigurationImportSelector.class)用于导入AutoConfigurationImportSelector类,后者负责选择并加载自动配置类。

1.1 AutoConfigurationImportSelector

AutoConfigurationImportSelector会根据各种条件注解(如@ConditionalOnClass@ConditionalOnMissingBean等)来决定是否导入某个自动配置类。

借 助AutoConf​igurat​ionImportSelector, @EnableAutoConf​igurat​ion可以帮助SpringBoot应用将所有符合条件的@Conf​igurat​ion配置都加载到当前SpringBoot创建并使用的IoC容器

1
2
3
4
5
6
public class AutoConfigurationImportSelector implements DeferredImportSelector, BeanClassLoaderAware,  
ResourceLoaderAware, BeanFactoryAware, EnvironmentAware, Ordered {



}

各个Aware 类和Ordered接口, 在 Spring IOC 容器启动过程拓展点一文中已经都介绍过,有需要可以点击查看。DeferredImportSelector 比较陌生,下面来介绍一下

1.2 DeferredImportSelector

1
2
3
4
5
6
7
8
9
10
11
12
public interface DeferredImportSelector extends ImportSelector {}


public interface ImportSelector {
String[] selectImports(AnnotationMetadata importingClassMetadata);

@Nullable
default Predicate<String> getExclusionFilter() {
return null;
}

}

DeferredImportSelector扩展了ImportSelector接口。DeferredImportSelector的主要作用是延迟配置类的导入,确保在所有常规的@Configuration类和@Import注解处理之后再进行处理。这种延迟处理机制提供了更大的灵活性,特别是在复杂的自动配置场景中,能够根据先前的配置结果决定是否导入额外的配置类。

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
// 处理和决定哪些自动配置类应该被包含或排除在 Spring Boot 应用程序的自动配置过程中。该方法通过一系列步骤和检查,最终返回一个包含自动配置类和排除类的 `AutoConfigurationEntry` 实例。
protected AutoConfigurationEntry getAutoConfigurationEntry(AnnotationMetadata annotationMetadata) {
// 调用 `isEnabled` 方法检查自动配置是否启用
// 如果未启用,返回一个空的自动配置条目 `EMPTY_ENTRY`
if (!isEnabled(annotationMetadata)) {
return EMPTY_ENTRY;
}
AnnotationAttributes attributes = getAttributes(annotationMetadata);
// 调用 `getCandidateConfigurations` 方法获取所有候选的自动配置类。
List<String> configurations = getCandidateConfigurations(annotationMetadata, attributes);
// 调用 `removeDuplicates` 方法,去除候选配置类列表中的重复项。
configurations = removeDuplicates(configurations);
// 调用 `getExclusions` 方法获取需要排除的自动配置类。
Set<String> exclusions = getExclusions(annotationMetadata, attributes);
// 调用 `checkExcludedClasses` 方法,检查候选配置类列表中是否包含任何需要排除的类,并进行相应处理。
checkExcludedClasses(configurations, exclusions);
// 从候选配置类列表中移除所有排除的类。
configurations.removeAll(exclusions);
// 进一步过滤候选配置类列表,保留需要的配置类。
configurations = getConfigurationClassFilter().filter(configurations);
// 触发自动配置导入事件
fireAutoConfigurationImportEvents(configurations, exclusions);
return new AutoConfigurationEntry(configurations, exclusions);
}


// SpringFactoriesLoader.loadFactoryNames加载文件其实在SpringApplication 阶段已经加载完成,所以这里会直接读取缓存里的数据,不会重复加载文件
protected List<String> getCandidateConfigurations(AnnotationMetadata metadata, AnnotationAttributes attributes) {
List<String> configurations = SpringFactoriesLoader.loadFactoryNames(getSpringFactoriesLoaderFactoryClass(),
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;
}

getCandidateConfigurations 查找所有满足条件的自动配置类

2. META-INF/spring.factories 文件

META-INF/spring.factories用于定义各种扩展点(如自动配置类、环境后处理器等)的实现类。

文件使用简单的键值对格式,每一行定义一个映射关系。键是接口或抽象类的完全限定名,值是实现类的完全限定名,多个实现类用逗号分隔。

反斜杠 \ 在属性文件中用于将长行拆分为多行。这样做的目的是为了使文件更易于阅读和维护。在 spring.factories 文件中,这通常用于定义多行值。

SpringBoot自动配置实现的过程中,会查找类路径下所有的META-INF/spring.factories文件。

所有指的是包括应用本身及其所有依赖JAR包中的META-INF/spring.factories文件。

在SpringBoot项目实际启动过程中,查找到的META-INF/spring.factories文件包括以下4个

  1. spring-boot-autoconfigure-2.3.4.RELEASE.jar META-INF/spring.factories
  2. spring-boot-2.3.4.RELEASE.jar META-INF/spring.factories
  3. spring-beans-5.2.9.RELEASE.jar META-INF/spring.factories
  4. mybatis-spring-boot-autoconfigure-2.1.4.jar META-INF/spring.factories

META-INF/spring.factories文件的具体加载逻辑在SpringFactoriesLoader。loadSpringFactories方法中具体实现

3. SpringFactoriesLoader

SpringFactoriesLoader.loadFactoryNames用来加载获取所有META-INF/spring.factories中的配置信息, 其加载流程大致有以下步骤

  1. 获取资源路径:loadSpringFactories方法首先会获取类加载器,并查找类路径下所有名为META-INF/spring.factories的资源文件。
  2. 读取并解析文件:对每个找到的META-INF/spring.factories文件,使用PropertiesLoaderUtils.loadProperties方法将其加载为Properties对象。

  3. 处理文件内容:遍历Properties对象的每一个条目,将键(工厂类的名称)和值(实现类的全限定名列表)存入结果Map中。

  4. 返回结果:返回一个Map,其中键是工厂类的名称,值是实现类名称的列表。

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
package org.springframework.core.io.support;

public final class SpringFactoriesLoader {

public static final String FACTORIES_RESOURCE_LOCATION = "META-INF/spring.factories";
private static final Map<ClassLoader, MultiValueMap<String, String>> cache = new ConcurrentReferenceHashMap<>();

private SpringFactoriesLoader() {
}

public static List<String> loadFactoryNames(Class<?> factoryType, @Nullable ClassLoader classLoader) {
String factoryTypeName = factoryType.getName();
return loadSpringFactories(classLoader).getOrDefault(factoryTypeName, Collections.emptyList());
}

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

try {
Enumeration<URL> urls = (classLoader != null ?
classLoader.getResources(FACTORIES_RESOURCE_LOCATION) :
ClassLoader.getSystemResources(FACTORIES_RESOURCE_LOCATION));
result = new LinkedMultiValueMap<>();
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();
for (String factoryImplementationName : StringUtils.commaDelimitedListToStringArray((String) entry.getValue())) {
result.add(factoryTypeName, factoryImplementationName.trim());
}
}
}
cache.put(classLoader, result);
return result;
}
catch (IOException ex) {
throw new IllegalArgumentException("Unable to load factories from location [" +
FACTORIES_RESOURCE_LOCATION + "]", ex);
}
}
}

针对META-INF/spring.factories的加载过程有2点需要注意

3.1 缓存机制

1
private static final Map<ClassLoader, MultiValueMap<String, String>> cache = new ConcurrentReferenceHashMap<>();

该缓存的作用是在同一个ClassLoader下,避免了对同一个spring.factories文件的重复加载,因为后面的代码有同样的流程。

所以该缓存的存在可以提高SpringBoot 项目的启动速度。

3.2 MultiValueMap

cache 缓存中的value 是MultiValueMap。
MultiValueMap 在实际开发中不太常用, 从debug信息中可以看到,就是同一个key 可以对应多个value 。
getOrDefault方法的执行逻辑可以描述如下:

  1. 检查键是否存在
    • 使用 containsKey 方法检查给定键是否存在于映射中。
  2. 返回值或默认值
    • 如果键存在,则返回与该键关联的值。
    • 如果键不存在,则返回提供的默认值。

      3.3 条件过滤

经过loadSpringFactories 处理 META-INF/spring.factories文件所有的配置信息均已经存储在cache中。

回到loadFactoryNames方法中,通过MultiValueMap.getOrDefault获取指定类型 的配置信息。

1
2
3
4
public static List<String> loadFactoryNames(Class<?> factoryType, @Nullable ClassLoader classLoader) {  
String factoryTypeName = factoryType.getName();
return loadSpringFactories(classLoader).getOrDefault(factoryTypeName, Collections.emptyList());
}

4. 自动配置类-@Configuration

Spring Boot的自动配置类通过一系列@Configuration类和条件注解来实现,并通过@EnableAutoConfiguration注解启用。

Spring IOC 容器启动过程拓展点 一文中提到过,在Spring IOC容器中,Bean的定义方式确实有三种,XML配置、注解配置和Java Config配置。

在实际业务开发中, Java Config 使用较少。 不过在SpringBoot 自动配置的实现过程中, Java config 有大量使用。

Java Config配置通过Java类和方法来定义和配置Bean,利用了Spring的@Configuration@Bean注解。

  • @Configuration 类:Spring 会扫描所有带有 @Configuration 注解的类。
  • 解析 @Bean 方法ConfigurationClassPostProcessor 会解析这些类中的 @Bean 方法。
  • 注册 BeanDefinition:对于每个 @Bean 方法,会被 ConfigurationClassPostProcessor 解析,Spring 会创建一个 BeanDefinition 对象,并将其注册到 BeanFactory 中。BeanDefinition 的名称默认是 @Bean 方法的方法名,除非在 @Bean 注解中显式指定了 name 属性。

    4.1 示例代码-MybatisLanguageDriverAutoConfiguration

    以在 mybatis-spring-boot-autoconfigure-2.1.4.jar META-INF/spring.factories 出现的MybatisLanguageDriverAutoConfiguration 为例看一下具体使用
    在自动配置类中,有我们熟悉的sqlSessionFactory
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
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
@Configuration
@ConditionalOnClass(LanguageDriver.class)
public class MybatisLanguageDriverAutoConfiguration {

private static final String CONFIGURATION_PROPERTY_PREFIX = "mybatis.scripting-language-driver";

/**
* Configuration class for mybatis-freemarker 1.1.x or under.
*/
@Configuration
@ConditionalOnClass(FreeMarkerLanguageDriver.class)
@ConditionalOnMissingClass("org.mybatis.scripting.freemarker.FreeMarkerLanguageDriverConfig")
public static class LegacyFreeMarkerConfiguration {
@Bean
@ConditionalOnMissingBean
FreeMarkerLanguageDriver freeMarkerLanguageDriver() {
return new FreeMarkerLanguageDriver();
}
}

/**
* Configuration class for mybatis-freemarker 1.2.x or above.
*/
@Configuration
@ConditionalOnClass({ FreeMarkerLanguageDriver.class, FreeMarkerLanguageDriverConfig.class })
public static class FreeMarkerConfiguration {
@Bean
@ConditionalOnMissingBean
FreeMarkerLanguageDriver freeMarkerLanguageDriver(FreeMarkerLanguageDriverConfig config) {
return new FreeMarkerLanguageDriver(config);
}

@Bean
@ConditionalOnMissingBean
@ConfigurationProperties(CONFIGURATION_PROPERTY_PREFIX + ".freemarker")
public FreeMarkerLanguageDriverConfig freeMarkerLanguageDriverConfig() {
return FreeMarkerLanguageDriverConfig.newInstance();
}
}

/**
* Configuration class for mybatis-velocity 2.0 or under.
*/
@Configuration
@ConditionalOnClass(org.mybatis.scripting.velocity.Driver.class)
@ConditionalOnMissingClass("org.mybatis.scripting.velocity.VelocityLanguageDriverConfig")
@SuppressWarnings("deprecation")
public static class LegacyVelocityConfiguration {
@Bean
@ConditionalOnMissingBean
org.mybatis.scripting.velocity.Driver velocityLanguageDriver() {
return new org.mybatis.scripting.velocity.Driver();
}
}

/**
* Configuration class for mybatis-velocity 2.1.x or above.
*/
@Configuration
@ConditionalOnClass({ VelocityLanguageDriver.class, VelocityLanguageDriverConfig.class })
public static class VelocityConfiguration {
@Bean
@ConditionalOnMissingBean
VelocityLanguageDriver velocityLanguageDriver(VelocityLanguageDriverConfig config) {
return new VelocityLanguageDriver(config);
}

@Bean
@ConditionalOnMissingBean
@ConfigurationProperties(CONFIGURATION_PROPERTY_PREFIX + ".velocity")
public VelocityLanguageDriverConfig velocityLanguageDriverConfig() {
return VelocityLanguageDriverConfig.newInstance();
}
}

@Configuration
@ConditionalOnClass(ThymeleafLanguageDriver.class)
public static class ThymeleafConfiguration {
@Bean
@ConditionalOnMissingBean
ThymeleafLanguageDriver thymeleafLanguageDriver(ThymeleafLanguageDriverConfig config) {
return new ThymeleafLanguageDriver(config);
}

@Bean
@ConditionalOnMissingBean
@ConfigurationProperties(CONFIGURATION_PROPERTY_PREFIX + ".thymeleaf")
public ThymeleafLanguageDriverConfig thymeleafLanguageDriverConfig() {
return ThymeleafLanguageDriverConfig.newInstance();
}

// This class provides to avoid the https://github.com/spring-projects/spring-boot/issues/21626 as workaround.
@SuppressWarnings("unused")
private static class MetadataThymeleafLanguageDriverConfig extends ThymeleafLanguageDriverConfig {

@ConfigurationProperties(CONFIGURATION_PROPERTY_PREFIX + ".thymeleaf.dialect")
@Override
public DialectConfig getDialect() {
return super.getDialect();
}

@ConfigurationProperties(CONFIGURATION_PROPERTY_PREFIX + ".thymeleaf.template-file")
@Override
public TemplateFileConfig getTemplateFile() {
return super.getTemplateFile();
}
}
}
}

4.2 条件配置 and 条件注解

自动配置类依赖于条件注解来确保只有在满足特定条件时才会进行配置。这些注解包括:

  • @ConditionalOnClass:只有在类路径中存在指定的类时,才会启用该配置。
  • @ConditionalOnMissingBean:只有在Spring上下文中不存在指定的Bean时,才会创建该Bean。
  • @ConditionalOnProperty:只有在配置文件中存在指定属性并且值匹配时,才会启用该配置。

4.3 排除自动配置

在某些情况下,开发者可能希望排除某些自动配置类。可以通过@SpringBootApplication注解的exclude属性来实现:

1
2
3
4
5
6
@SpringBootApplication(exclude = {DataSourceAutoConfiguration.class})
public class MyApplication {
public static void main(String[] args) {
SpringApplication.run(MyApplication.class, args);
}
}

或者在配置文件中排除:

1
spring.autoconfigure.exclude=org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration

4.4 自定义自动配置

开发者可以创建自定义的自动配置类,以满足特定需求。自定义自动配置类需要使用@Configuration和条件注解,并将其打包到JAR文件中,以便在其他Spring Boot应用中使用。例如:

1
2
3
4
5
6
7
8
9
10
@Configuration
@ConditionalOnClass(MyCustomService.class)
public class MyCustomAutoConfiguration {

@Bean
@ConditionalOnMissingBean
public MyCustomService myCustomService() {
return new MyCustomServiceImpl();
}
}

5. ConfigurationClassPostProcessor

1
2
3
4
public class ConfigurationClassPostProcessor implements BeanDefinitionRegistryPostProcessor,  
PriorityOrdered, ResourceLoaderAware, BeanClassLoaderAware, EnvironmentAware {

}

ConfigurationClassPostProcessor 的职责 主要有两个

  1. 解析@Configuration及其相关注解成BeanDefinition
  2. 将解析得到的 BeanDefinition 注册到 BeanFactory 中。

解析的注解包括以下内容

  • @Configuration:解析所有标记为 @Configuration 的类, 所有自动配置类均有@Configuration注解。
  • @ComponentScan 注解:处理 @ComponentScan 注解,扫描指定包路径下的组件(如 @Component, @Repository, @Service, @Controller 等注解标记的类)。
  • @Import 注解:处理 @Import 注解,导入其他配置类或处理 ImportSelectorImportBeanDefinitionRegistrar
  • @Bean 方法:解析 @Bean 方法,将其定义的 bean 注册为 BeanDefinition
  • @PropertySource 注解:处理 @PropertySource 注解,加载属性源文件。

5.1 实现继承关系

5.1.1 BeanFactoryPostProcessor

从实现继承图中可以看出, ConfigurationClassPostProcessor实现了BeanFactoryPostProcessor接口,BeanFactoryPostProcessor的作用时机是invokeBeanFactoryPostProcessors

关于BeanFactoryPostProcessor, 更多可以阅读 Spring IOC 容器启动过程拓展点

5.1.2 BeanDefinitionRegistryPostProcessor

关于BeanDefinitionRegistryPostProcessor, Spring IOC 容器启动过程拓展点已经介绍过,它继承了BeanFactoryPostProcessor , 并增加了一个方法。

1
2
3
4
5
public interface BeanDefinitionRegistryPostProcessor extends BeanFactoryPostProcessor {  

void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) throws BeansException;

}

ConfigurationClassPostProcessor中,postProcessBeanDefinitionRegistry方法会被调用,用于处理配置类和自动配置类。

5.2 internalConfigurationAnnotationProcessor

org.springframework.context.annotation.internalConfigurationAnnotationProcessor是Spring框架内部使用的一个特殊的Bean名称,用于标识和注册ConfigurationClassPostProcessor的实例。

这是Spring框架内部使用的一种机制,用于在Spring容器启动时处理@Configuration注解及相关配置。

1
2
3
4
5
6
7
8
public abstract class AnnotationConfigUtils {  

/**
* The bean name of the internally managed Configuration annotation processor.
*/
public static final String CONFIGURATION_ANNOTATION_PROCESSOR_BEAN_NAME =
"org.springframework.context.annotation.internalConfigurationAnnotationProcessor";
}

在 Spring 容器启动过程中,ConfigurationClassPostProcessor 会进行以下步骤:

  1. 扫描 MybatisLanguageDriverAutoConfiguration:识别该类是一个配置类。
  2. 解析 @Bean 方法
    • 识别 defaultLanguageDriver 方法和 anotherLanguageDriver 方法上的 @Bean 注解。
  3. 创建 BeanDefinition
    • 为每个 @Bean 方法创建一个 BeanDefinition 对象。
  4. 注册 BeanDefinition
    • 使用 defaultLanguageDriver 作为 beanName 注册 defaultLanguageDriver 方法的 BeanDefinition
    • 使用 anotherLanguageDriver 作为 beanName 注册 anotherLanguageDriver 方法的 BeanDefinition

最终,Spring 容器中会有两个 bean,它们的名称分别是 defaultLanguageDriveranotherLanguageDriver,对应的 BeanDefinition 是通过解析 @Bean 方法得到的。

6. ApplicationContextInitializer 接口

在 Spring Boot 中,ApplicationContextInitializer 是一个扩展点接口,主要用于在应用上下文ConfigurableApplicationContext 执行一在些refresh之前的额外配置。

1
2
3
4
public interface ApplicationContextInitializer<C extends ConfigurableApplicationContext> {  

void initialize(C applicationContext);
}

Spring Boot 提供了一些内置的 ApplicationContextInitializer 实现,它们在应用启动过程中起着重要的作用。

  1. SharedMetadataReaderFactoryContextInitializer:用于共享 MetadataReaderFactory
  2. ConditionEvaluationReportLoggingListener:用于在条件评估报告时记录日志。
  3. ConfigurationWarningsApplicationContextInitializer:用于在配置警告时初始化应用上下文。

在自动配置实现的过程中,ApplicationContextInitializer非常重要,其具体实现类SharedMetadataReaderFactoryContextInitializerConfigurationClassPostProcessor有密切关系。

6.1 注册方式

可以通过多种方式注册 ApplicationContextInitializer,以下是几种常见的方法:

6.1.1 通过 Spring Boot 的 SpringApplication

在 Spring Boot 应用中,可以在 SpringApplication 中注册 ApplicationContextInitializer

1
2
3
4
5
6
7
public class MyApplication {
public static void main(String[] args) {
SpringApplication application = new SpringApplication(MyApplication.class);
application.addInitializers(new MyApplicationContextInitializer());
application.run(args);
}
}

6.1.2 通过 META-INF/spring.factories

可以在 META-INF/spring.factories 文件中声明 ApplicationContextInitializer

1
org.springframework.context.ApplicationContextInitializer=com.example.MyApplicationContextInitializer

7. SharedMetadataReaderFactoryContextInitializer

SharedMetadataReaderFactoryContextInitializer的作用是Spring 应用程序上下文初始化期间,提供一个共享的 MetadataReaderFactory 实例,并通过缓存元数据读取来提高性能。

SharedMetadataReaderFactoryContextInitializer 通过在 Spring 应用程序启动期间注册和配置共享的 MetadataReaderFactory 实现了优化性能的目的。其主要作用是确保所有需要读取元数据的组件共享同一个 MetadataReaderFactory 实例,从而减少重复的元数据读取操作,提高启动和运行效率。

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
class SharedMetadataReaderFactoryContextInitializer
implements ApplicationContextInitializer<ConfigurableApplicationContext>, Ordered {

// 这个常量定义了共享 `MetadataReaderFactory` 实例的 Bean 名称, 这是Sping 内部标识名称
public static final String BEAN_NAME = "org.springframework.boot.autoconfigure."
+ "internalCachingMetadataReaderFactory";

// 实现 `ApplicationContextInitializer` 的 `initialize` 方法,在应用上下文初始化时调用。
// 向应用上下文添加一个 `CachingMetadataReaderFactoryPostProcessor` 实例。
@Override
public void initialize(ConfigurableApplicationContext applicationContext) {
applicationContext.addBeanFactoryPostProcessor(new CachingMetadataReaderFactoryPostProcessor());
}

@Override
public int getOrder() {
return 0;
}

/**
* {@link BeanDefinitionRegistryPostProcessor} to register the
* {@link CachingMetadataReaderFactory} and configure the
* {@link ConfigurationClassPostProcessor}.
*/
//静态内部类,负责注册共享的 `MetadataReaderFactory` 并配置 `ConfigurationClassPostProcessor`。
private static class CachingMetadataReaderFactoryPostProcessor
implements BeanDefinitionRegistryPostProcessor, PriorityOrdered {

/**
* {@link FactoryBean} to create the shared {@link MetadataReaderFactory}.
*/
// 内部静态类,用于创建共享的 `MetadataReaderFactory` 实例。
static class SharedMetadataReaderFactoryBean
implements FactoryBean<ConcurrentReferenceCachingMetadataReaderFactory>, BeanClassLoaderAware,
ApplicationListener<ContextRefreshedEvent> {

private ConcurrentReferenceCachingMetadataReaderFactory metadataReaderFactory;

@Override
public void setBeanClassLoader(ClassLoader classLoader) {
this.metadataReaderFactory = new ConcurrentReferenceCachingMetadataReaderFactory(classLoader);
}

@Override
public ConcurrentReferenceCachingMetadataReaderFactory getObject() throws Exception {
return this.metadataReaderFactory;
}

@Override
public Class<?> getObjectType() {
return CachingMetadataReaderFactory.class;
}

@Override
public boolean isSingleton() {
return true;
}

@Override
public void onApplicationEvent(ContextRefreshedEvent event) {
this.metadataReaderFactory.clearCache();
}

}
}

7.1 CachingMetadataReaderFactoryPostProcessor

CachingMetadataReaderFactoryPostProcessorSharedMetadataReaderFactoryContextInitializer的一个静态内部类, 它实现了BeanDefinitionRegistryPostProcessor, PriorityOrdered两个接口。

关于BeanDefinitionRegistryPostProcessor, PriorityOrderedSpring IOC 容器启动过程拓展点已经介绍过

  1. BeanDefinitionRegistryPostProcessor 继承了BeanFactoryPostProcessor , 并增加了一个方法

  2. PriorityOrderedOrdered接口的一个子接口,允许BeanFactoryPostProcessor在其他普通Ordered执行。这主要用于那些必须首先应用的处理器,比如那些涉及配置如何加载的处理器。

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
private static class CachingMetadataReaderFactoryPostProcessor
implements BeanDefinitionRegistryPostProcessor, PriorityOrdered {

@Override
public int getOrder() {
// Must happen before the ConfigurationClassPostProcessor is created
return Ordered.HIGHEST_PRECEDENCE;
}

@Override
public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
}

@Override
public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) throws BeansException {
// 注册共享的 `MetadataReaderFactory`。
register(registry);
// 配置 `ConfigurationClassPostProcessor`
configureConfigurationClassPostProcessor(registry);
}

// 向注册表中添加一个 `SharedMetadataReaderFactoryBean` 的 Bean 定义。
private void register(BeanDefinitionRegistry registry) {
BeanDefinition definition = BeanDefinitionBuilder
.genericBeanDefinition(SharedMetadataReaderFactoryBean.class, SharedMetadataReaderFactoryBean::new)
.getBeanDefinition();
registry.registerBeanDefinition(BEAN_NAME, definition);
}
// 配置 `ConfigurationClassPostProcessor`, 将共享的 `MetadataReaderFactory` 关联到其 `metadataReaderFactory` 属性。
private void configureConfigurationClassPostProcessor(BeanDefinitionRegistry registry) {
try {
BeanDefinition definition = registry
.getBeanDefinition(AnnotationConfigUtils.CONFIGURATION_ANNOTATION_PROCESSOR_BEAN_NAME);
definition.getPropertyValues().add("metadataReaderFactory", new RuntimeBeanReference(BEAN_NAME));
}
catch (NoSuchBeanDefinitionException ex) {
}
}

}

7.1.1 postProcessBeanFactory

BeanFactoryPostProcessor 中定义的方法, CachingMetadataReaderFactoryPostProcessor对该方法是空实现

1
2
3
4
5
@FunctionalInterface  
public interface BeanFactoryPostProcessor {
void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException;

}

7.1.2 postProcessBeanDefinitionRegistry

BeanDefinitionRegistryPostProcessor中定义的接口

1
2
3
public interface BeanDefinitionRegistryPostProcessor extends BeanFactoryPostProcessor {  
void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) throws BeansException;
}

CachingMetadataReaderFactoryPostProcessor 重写该方法时包含2个重要步骤

1
2
3
4
5
6
7
	@Override
public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) throws BeansException {
// 注册共享的 `MetadataReaderFactory`。
register(registry);
// 配置 `ConfigurationClassPostProcessor`
configureConfigurationClassPostProcessor(registry);
}

7.1.2.1 register-SharedMetadataReaderFactoryBean的BeanDefinition注册

向注册表中添加一个 SharedMetadataReaderFactoryBean 的 Bean 定义。

1
2
3
4
5
6
7
8
9
private static class CachingMetadataReaderFactoryPostProcessor{
// 向注册表中添加一个 `SharedMetadataReaderFactoryBean` 的 Bean 定义。
private void register(BeanDefinitionRegistry registry) {
BeanDefinition definition = BeanDefinitionBuilder
.genericBeanDefinition(SharedMetadataReaderFactoryBean.class, SharedMetadataReaderFactoryBean::new)
.getBeanDefinition();
registry.registerBeanDefinition(BEAN_NAME, definition);
}
}

从代码中可以看到, SharedMetadataReaderFactoryBean的bean 定义注册是通过内部标识org.springframework.boot.autoconfigure.internalCachingMetadataReaderFactory 完成的, 相当于在bean 实例化的过程中, 遇到beanName 是org.springframework.boot.autoconfigure.internalCachingMetadataReaderFactory 时,就知道需要实例化SharedMetadataReaderFactoryBean 这个工厂bean

7.1.2.2 configureConfigurationClassPostProcessor

配置 ConfigurationClassPostProcessor, 将共享的 MetadataReaderFactory 关联到其 metadataReaderFactory 属性。

1
2
3
4
5
6
7
8
9
10
private void configureConfigurationClassPostProcessor(BeanDefinitionRegistry registry) {
try {
BeanDefinition definition = registry
.getBeanDefinition(AnnotationConfigUtils.CONFIGURATION_ANNOTATION_PROCESSOR_BEAN_NAME);
definition.getPropertyValues().add("metadataReaderFactory", new RuntimeBeanReference(BEAN_NAME));
}
catch (NoSuchBeanDefinitionException ex) {
}
}
}

从代码中可以看到, ConfigurationClassPostProcessor的bean 定义注册也是通过内部特使标识完成的, 其标识是org.springframework.context.annotation.internalConfigurationAnnotationProcessor 相当于在bean 实例化的过程中, 遇到beanName 是org.springframework.context.annotation.internalConfigurationAnnotationProcessor 时,就知道需要实例化 ConfigurationClassPostProcessor 这个类。

7.2 SharedMetadataReaderFactoryBean

在6.1.2.1 中注册的BeanDefinitionSharedMetadataReaderFactoryBean

SharedMetadataReaderFactoryBean也是SharedMetadataReaderFactoryContextInitializer的一个静态内部类, 它是一个FactoryBean

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
static class SharedMetadataReaderFactoryBean
implements FactoryBean<ConcurrentReferenceCachingMetadataReaderFactory>, BeanClassLoaderAware,
ApplicationListener<ContextRefreshedEvent> {

private ConcurrentReferenceCachingMetadataReaderFactory metadataReaderFactory;

@Override
public void setBeanClassLoader(ClassLoader classLoader) {
this.metadataReaderFactory = new ConcurrentReferenceCachingMetadataReaderFactory(classLoader);
}

@Override
public ConcurrentReferenceCachingMetadataReaderFactory getObject() throws Exception {
return this.metadataReaderFactory;
}

@Override
public Class<?> getObjectType() {
return CachingMetadataReaderFactory.class;
}

@Override
public boolean isSingleton() {
return true;
}

@Override
public void onApplicationEvent(ContextRefreshedEvent event) {
this.metadataReaderFactory.clearCache();
}

}

7.2.1 ConcurrentReferenceCachingMetadataReaderFactory

ConcurrentReferenceCachingMetadataReaderFactory 是 Spring Framework 中一个用于缓存和并发优化的类,专门用于读取类的元数据(如注解、方法、字段等)时提高性能。它通过使用并发数据结构和缓存机制,显著减少了重复的元数据读取操作,从而提升了性能。

以上都是SpringBoot 自动配置机制实现过程中会涉及到的重要知识点,提前了解他们有助于帮助更好地了解SpringBoot 自动配置的实现。

现在思考,自动配置类是如何从配置文件中的一行文字变成Spring 容器中可实际发挥作用的实例bean

  1. 加载自动配置类名称:读取META-INF/spring.factories文件,找到所有的自动配置类,由 SpringFactoriesLoader.loadFactoryNames完成
  2. 注册自动配置类BeanDefinition:所有的自动配置类如果想成为实例bean, 要在Spring 容器BeanFactory中先有BeanDefinition , 自动配置类BeanDefinition的生成由ConfigurationClassPostProcessor 完成
  3. 自动配置类的的实例化:根据BeanDefinition 实例化自动配置类。自动配置类有了bean definition 后, 就可以通过getBean流程被实例成bean, 即getBean

Spring bean 实例化一文中,已经详细介绍了以refresh方法为入口的Spring IOC 容器启动过程,不论是以哪种方式启动, refresh 都是入口, 例如ClassPathXmlApplicationContext 方式refresh也是入口

1
ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");

我们需要来看下, 在SpringBoot 启动的Spring 项目中, 在进入refresh入口前进行了哪些操作,这些都是SpringBoot 实现自动配置的重要步骤

8. 加载自动配置类名称

我们在分析 Spring bean 实例化时, 只分析了以refresh方法为入口的代码, 如果想要充分了解SpringBoot 自动配置的机制, 不只要了解refresh 里面的流程,还要分析SpringApplication.run为入口的代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
public class CodingInActionApplication {   
public static void main(String[] args) { SpringApplication.run(CodingInActionApplication.class, args);
}

public class SpringApplication {

/**
* The class name of application context that will be used by default for web
* environments.
*/
public static final String DEFAULT_SERVLET_WEB_CONTEXT_CLASS = "org.springframework.boot."
+ "web.servlet.context.AnnotationConfigServletWebServerApplicationContext";


public static ConfigurableApplicationContext run(Class<?> primarySource, String... args) {
return run(new Class<?>[] { primarySource }, args);
}

public static ConfigurableApplicationContext run(Class<?>[] primarySources, String[] args) {
return new SpringApplication(primarySources).run(args);
}
}

8.1 new SpringApplication

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
public class SpringApplication {
// 以下是俩构造函数, 重点看第二个
public SpringApplication(Class<?>... primarySources) {
this(null, primarySources);
}

public SpringApplication(ResourceLoader resourceLoader, Class<?>... primarySources) {
this.resourceLoader = resourceLoader;
Assert.notNull(primarySources, "PrimarySources must not be null");
this.primarySources = new LinkedHashSet<>(Arrays.asList(primarySources));
this.webApplicationType = WebApplicationType.deduceFromClasspath();
setInitializers((Collection) getSpringFactoriesInstances(ApplicationContextInitializer.class));
setListeners((Collection) getSpringFactoriesInstances(ApplicationListener.class));
this.mainApplicationClass = deduceMainApplicationClass();
}

private <T> Collection<T> getSpringFactoriesInstances(Class<T> type) {
return getSpringFactoriesInstances(type, new Class<?>[] {});
}


private <T> Collection<T> getSpringFactoriesInstances(Class<T> type, Class<?>[] parameterTypes, Object... args) {
ClassLoader classLoader = getClassLoader();
// Use names and ensure unique to protect against duplicates
Set<String> names = new LinkedHashSet<>(SpringFactoriesLoader.loadFactoryNames(type, classLoader));
List<T> instances = createSpringFactoriesInstances(type, parameterTypes, classLoader, args, names);
AnnotationAwareOrderComparator.sort(instances);
return instances;
}

private <T> List<T> createSpringFactoriesInstances(Class<T> type, Class<?>[] parameterTypes,
ClassLoader classLoader, Object[] args, Set<String> names) {
List<T> instances = new ArrayList<>(names.size());
for (String name : names) {
try {
Class<?> instanceClass = ClassUtils.forName(name, classLoader);
Assert.isAssignable(type, instanceClass);
Constructor<?> constructor = instanceClass.getDeclaredConstructor(parameterTypes);
T instance = (T) BeanUtils.instantiateClass(constructor, args);
instances.add(instance);
}
catch (Throwable ex) {
throw new IllegalArgumentException("Cannot instantiate " + type + " : " + name, ex);
}
}
return instances;
}
}

8.1.1 setInitializers

8.1.2 SpringFactoriesLoader.loadFactoryNames

SpringApplication.run 为入口深入源码, 可以在SpringApplication的构造函数中看到如下代码,

1
2
3
4
5
6
7
8
9
public SpringApplication(ResourceLoader resourceLoader, Class<?>... primarySources) {  
this.resourceLoader = resourceLoader;
Assert.notNull(primarySources, "PrimarySources must not be null");
this.primarySources = new LinkedHashSet<>(Arrays.asList(primarySources));
this.webApplicationType = WebApplicationType.deduceFromClasspath();
setInitializers((Collection) getSpringFactoriesInstances(ApplicationContextInitializer.class));
setListeners((Collection) getSpringFactoriesInstances(ApplicationListener.class));
this.mainApplicationClass = deduceMainApplicationClass();
}

getSpringFactoriesInstances方法中调用了SpringFactoriesLoader.loadFactoryNames, 该方法完成了对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
private <T> Collection<T> getSpringFactoriesInstances(Class<T> type) {  
return getSpringFactoriesInstances(type, new Class<?>[] {});
}


private <T> Collection<T> getSpringFactoriesInstances(Class<T> type, Class<?>[] parameterTypes, Object... args) {
ClassLoader classLoader = getClassLoader();
Set<String> names = new LinkedHashSet<>(SpringFactoriesLoader.loadFactoryNames(type, classLoader));
List<T> instances = createSpringFactoriesInstances(type, parameterTypes, classLoader, args, names);
AnnotationAwareOrderComparator.sort(instances);
return instances;
}

private <T> List<T> createSpringFactoriesInstances(Class<T> type, Class<?>[] parameterTypes,
ClassLoader classLoader, Object[] args, Set<String> names) {
List<T> instances = new ArrayList<>(names.size());
for (String name : names) {
try {
Class<?> instanceClass = ClassUtils.forName(name, classLoader);
Assert.isAssignable(type, instanceClass);
Constructor<?> constructor = instanceClass.getDeclaredConstructor(parameterTypes);
T instance = (T) BeanUtils.instantiateClass(constructor, args);
instances.add(instance);
}
catch (Throwable ex) {
throw new IllegalArgumentException("Cannot instantiate " + type + " : " + name, ex);
}
}
return instances;
}

根据前文说过,在SpringBoot项目实际启动过程中,查找到的META-INF/spring.factories文件包括以下4个

  1. spring-boot-autoconfigure-2.3.4.RELEASE.jar META-INF/spring.factories
  2. spring-boot-2.3.4.RELEASE.jar META-INF/spring.factories
  3. spring-beans-5.2.9.RELEASE.jar META-INF/spring.factories
  4. mybatis-spring-boot-autoconfigure-2.1.4.jar META-INF/spring.factories

从这4个文件中, 一共找到13个key。

经过loadSpringFactories 处理, 4个META-INF/spring.factories文件所有的配置信息均已经存储在result 这个Map 中的。

回到loadFactoryNames方法中,通过MultiValueMapgetOrDefault获取指定类型 的配置信息。

1
2
3
4
public static List<String> loadFactoryNames(Class<?> factoryType, @Nullable ClassLoader classLoader) {  
String factoryTypeName = factoryType.getName();
return loadSpringFactories(classLoader).getOrDefault(factoryTypeName, Collections.emptyList());
}

setInitializers方法中, 需要的是 org.springframework.context.ApplicationContextInitializer 对应的自动配置类。

1
setInitializers((Collection) getSpringFactoriesInstances(ApplicationContextInitializer.class)); 

从图中可以看出, 满足条件的自动配置类有7个, 接下来我们会重点关注其中的org.springframework.boot.autoconfigure.SharedMetadataReaderFactoryContextInitializer

8.1.3 反射-createSpringFactoriesInstances

获取到满足满足条件的自动配置类全限定类名后,就是用经典的反射流程完成相应类的实例化。
关于反射,可以点击阅读 java 反射 实践与原理

8.2 run

在SpringApplication 实例化完成后,开始执行run逻辑,其中refreshContext 进去后,就是 Spring 容器的启动过程,创建 BeanFactory、以及BeanFactory 容器中各个bean 的实例化过程。

在 Spring 容器的启动之前,先来看下ApplicationContext 做了哪些准备
⚠️:这里我们还是要区分以下BeanFactoryApplicationContext
Spring IOC 容器启动过程拓展点一文中曾提到过,BeanFactory是Spring框架中最基础的IOC容器。它提供了基本的依赖注入机制,负责管理Bean的实例化、配置和生命周期。ApplicationContext是在BeanFactory基础上扩展的高级容器,提供了更多面向应用的功能,它还提供了国际化支持和框架事件体系,更易于创建实际应用。
一般称BeanFactory为IoC容器,而称ApplicationContext为应用上下文。

1
2
3
4
5
// 该方法只保留了部分代码
public ConfigurableApplicationContext run(String... args) {
prepareContext(context, environment, listeners, applicationArguments, printedBanner);
refreshContext(context);
}

8.2.1 prepareContext

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
//该方法只保留了部分代码
private void prepareContext(ConfigurableApplicationContext context, ConfigurableEnvironment environment,
SpringApplicationRunListeners listeners, ApplicationArguments applicationArguments, Banner printedBanner) {
applyInitializers(context);
}

protected void applyInitializers(ConfigurableApplicationContext context) {
for (ApplicationContextInitializer initializer : getInitializers()) {
Class<?> requiredType = GenericTypeResolver.resolveTypeArgument(initializer.getClass(),
ApplicationContextInitializer.class);
Assert.isInstanceOf(requiredType, context, "Unable to call initializer.");
// 调用个ApplicationContextInitializer的具体实现类的initialize方法
initializer.initialize(context);
}
}

8.2.2 applyInitializers

1
2
3
4
5
//该方法只保留了部分代码
private void prepareContext(ConfigurableApplicationContext context, ConfigurableEnvironment environment,
SpringApplicationRunListeners listeners, ApplicationArguments applicationArguments, Banner printedBanner) {
applyInitializers(context);
}

preContext 逻辑中, 只重点关注applyInitializers, 在SpringApplication.setInitializers方法中设置了从配置文件读取并通过反射创建7个ApplicationContextInitializer的具体实现类实例。 每个实现类在这里都会执行重写的initialize 方法

8.2.2 SharedMetadataReaderFactoryContextInitializer

ApplicationContextInitializer的7个具体实现类实例中, 关注
SharedMetadataReaderFactoryContextInitializer

从代码中可以看到SharedMetadataReaderFactoryContextInitializer.initialize的逻辑是将 CachingMetadataReaderFactoryPostProcessor 这个BeanFactoryPostProcessor 添加到应用上下文 ApplicationContext中进行记录管理。

1
2
3
4
5
6
7
8
9
public abstract class AbstractApplicationContext extends DefaultResourceLoader  
implements ConfigurableApplicationContext {
private final List<BeanFactoryPostProcessor> beanFactoryPostProcessors = new ArrayList<>();

public void addBeanFactoryPostProcessor(BeanFactoryPostProcessor postProcessor) {
Assert.notNull(postProcessor, "BeanFactoryPostProcessor must not be null");
this.beanFactoryPostProcessors.add(postProcessor);
}
}

以上内容都还是在应用上下文中进行处理,我们已经将配置在所有META-INF/spring.factories文件中的信息全部解析完成,并将配置信息存储在了SpringFactoriesLoadercache, 方便后面流程快速读取,接下来将分析进入refresh 后,自动配置类的处理过程。

9. 注册自动配置类的BeanDefinition

9.1 invokeBeanFactoryPostProcessors

Spring IOC 容器启动过程拓展点一文中,已经讲过,BeanFactoryPostProcessor 是 Spring 框架在bean 开始整个创建流程之前 起作用。其具体时机是refresh 中的invokeBeanFactoryPostProcessors方法

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 abstract class AbstractApplicationContext extends DefaultResourceLoader  
implements ConfigurableApplicationContext {
@Override
public void refresh() throws BeansException, IllegalStateException {

// 1. 创建beanFactory
ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();

// 2.BeanFactoryPostProcessor起作用
invokeBeanFactoryPostProcessors(beanFactory);

// 3.注册 BeanPostProcessor
registerBeanPostProcessors(beanFactory);

// 4. bean的生命周期管理和依赖关系的装配
finishBeanFactoryInitialization(beanFactory);
}

// 只保留重点代码
protected void invokeBeanFactoryPostProcessors(ConfigurableListableBeanFactory beanFactory) { PostProcessorRegistrationDelegate.invokeBeanFactoryPostProcessors(beanFactory, getBeanFactoryPostProcessors())
}

public List<BeanFactoryPostProcessor> getBeanFactoryPostProcessors() {
return this.beanFactoryPostProcessors;
}
}

接下来的内容,要重点分析在SharedMetadataReaderFactoryContextInitializer.initialize方法中创建的BeanFactoryPostProcessor : CachingMetadataReaderFactoryPostProcessor

9.2 CachingMetadataReaderFactoryPostProcessor

前面讲过,在applyInitializers逻辑中,SharedMetadataReaderFactoryContextInitializer.initialize的逻辑是将 CachingMetadataReaderFactoryPostProcessor 这个BeanFactoryPostProcessor 添加到应用上下文 ApplicationContext中进行记录管理。

同时CachingMetadataReaderFactoryPostProcessor 也是一个BeanDefinitionRegistryPostProcessor, 在 PostProcessorRegistrationDelegate.invokeBeanFactoryPostProcessors逻辑中调用其重写的postProcessBeanDefinitionRegistry,进行
SharedMetadataReaderFactoryBean
ConfigurationClassPostProcessorBeanDefinition注册

9.3 ConfigurationClassPostProcessor

现在当前Spring 容器beanFactory 中已经有了ConfigurationClassPostProcessor的的BeanDefinition,
同时ConfigurationClassPostProcessor 也是一个BeanDefinitionRegistryPostProcessor

1
2
3
4
public class ConfigurationClassPostProcessor implements BeanDefinitionRegistryPostProcessor,  
PriorityOrdered, ResourceLoaderAware, BeanClassLoaderAware, EnvironmentAware {

}

所以当invokeBeanFactoryPostProcessors方法执行到如下逻辑时,ConfigurationClassPostProcessor对应的beanName org.springframework.context.annotation.internalConfigurationAnnotationProcessor 会返回

1
2
3
public static void invokeBeanFactoryPostProcessors(  
ConfigurableListableBeanFactory beanFactory, List<BeanFactoryPostProcessor> beanFactoryPostProcessors) { beanFactory.getBeanNamesForType(BeanDefinitionRegistryPostProcessor.class, true, false);
}

beanFactory.getBean会触发ConfigurationClassPostProcessor的实例化过程

9.4 postProcessBeanDefinitionRegistry

ConfigurationClassPostProcessor的实例化完成后,继续执行`invokeBeanDefinitionRegistryPostProcessors

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
invokeBeanDefinitionRegistryPostProcessors(currentRegistryProcessors, registry)
````
会去调用`ConfigurationClassPostProcessor`中重写的`BeanDefinitionRegistryPostProcessor.postProcessBeanDefinitionRegistry` 方法,
{% asset_img 17.png %}

在`processConfigBeanDefinitions` 方法中,会触发解析项目中所有`@Configuration` 类及其相关注解。在这个过程中,具体来说,它处理以下内容:

- **`@Configuration` 类**:解析所有标记为 `@Configuration` 的类, 所有自动配置类均有`@Configuration`注解。
- **`@ComponentScan` 注解**:处理 `@ComponentScan` 注解,扫描指定包路径下的组件(如 `@Component`, `@Repository`, `@Service`, `@Controller` 等注解标记的类)。
- **`@Import` 注解**:处理 `@Import` 注解,导入其他配置类或处理 `ImportSelector` 和 `ImportBeanDefinitionRegistrar`。
- **`@Bean` 方法**:解析 `@Bean` 方法,将其定义的 bean 注册为 `BeanDefinition`。
- **`@PropertySource` 注解**:处理 `@PropertySource` 注解,加载属性源文件。

```java
public class ConfigurationClassPostProcessor implements BeanDefinitionRegistryPostProcessor,
PriorityOrdered, ResourceLoaderAware, BeanClassLoaderAware, EnvironmentAware {
// 只保留重点逻辑,省略了部分代码
public void processConfigBeanDefinitions(BeanDefinitionRegistry registry) {
List<BeanDefinitionHolder> configCandidates = new ArrayList<>();
// 获取当前beanFactory中,所有的BeanDefinitionName
String[] candidateNames = registry.getBeanDefinitionNames();

// Parse each @Configuration class
ConfigurationClassParser parser = new ConfigurationClassParser(
this.metadataReaderFactory, this.problemReporter, this.environment,
this.resourceLoader, this.componentScanBeanNameGenerator, registry);

Set<BeanDefinitionHolder> candidates = new LinkedHashSet<>(configCandidates);
Set<ConfigurationClass> alreadyParsed = new HashSet<>(configCandidates.size());
do {
parser.parse(candidates);
Set<ConfigurationClass> configClasses = new LinkedHashSet<>(parser.getConfigurationClasses());
this.reader.loadBeanDefinitions(configClasses);
candidates.clear();
}
while (!candidates.isEmpty());
}
}

9.4.1 获取解析候选类

获取当前beanFactory中, 所有 BeanDefinition 名称,检查每个对应的 BeanDefinition, 找出被@Configuretion 标注且还未处理的类, 显然被@SpringBootApplication 注解标注的启动类名称是符合条件的

1
2
3
4
5
6
7
8
9
10
11
12
13
14
List<BeanDefinitionHolder> configCandidates = new ArrayList<>();
// 获取当前beanFactory中,所有的BeanDefinitionName
String[] candidateNames = registry.getBeanDefinitionNames();
for (String beanName : candidateNames) {
BeanDefinition beanDef = registry.getBeanDefinition(beanName);
if (beanDef.getAttribute(ConfigurationClassUtils.CONFIGURATION_CLASS_ATTRIBUTE) != null) {
if (logger.isDebugEnabled()) {
logger.debug("Bean definition has already been processed as a configuration class: " + beanDef);
}
}
else if (ConfigurationClassUtils.checkConfigurationClassCandidate(beanDef, this.metadataReaderFactory)) {
configCandidates.add(new BeanDefinitionHolder(beanDef, beanName));
}
}

9.4.2 ConfigurationClassParser

前面我们说过,ConfigurationClassPostProcessor 的职责 主要有两个

  1. @Configuration及其相关注解,解析成BeanDefinition
  2. 将解析得到的 BeanDefinition 注册到 BeanFactory 中。

其实实际执行解析工作的核心组件是 ConfigurationClassParser

循环处理过滤出的候选类,使用ConfigurationClassParser 对候选配置进行解析直到所有配置类都被解析和注册。

1
2
3
4
5
ConfigurationClassParser parser = new ConfigurationClassParser(
this.metadataReaderFactory, this.problemReporter, this.environment,
this.resourceLoader, this.componentScanBeanNameGenerator, registry);

parser.parse(candidates);

针对不同类的BeanDefinition进行不同的parse 操作, 一个SpringBoot 项目,其启动代码标注的注解@SpringBootApplicationAnnotatedBeanDefinition类型的注解 , 所以这里是我们需要关注的逻辑

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
class ConfigurationClassParser {
public void parse(Set<BeanDefinitionHolder> configCandidates) {
for (BeanDefinitionHolder holder : configCandidates) {
BeanDefinition bd = holder.getBeanDefinition();
try {
if (bd instanceof AnnotatedBeanDefinition) {
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);
}
}

this.deferredImportSelectorHandler.process();
}

protected final void parse(AnnotationMetadata metadata, String beanName) throws IOException {
processConfigurationClass(new ConfigurationClass(metadata, beanName), DEFAULT_EXCLUSION_FILTER);
}
}

9.4.3 parse

解析的过程,通过parse 的递归完成项目中所有BeanDefinition的定义

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
// 只保留了部分代码
protected void processConfigurationClass(ConfigurationClass configClass, Predicate<String> filter) throws IOException {
if (this.conditionEvaluator.shouldSkip(configClass.getMetadata(), ConfigurationPhase.PARSE_CONFIGURATION)) {
return;
}
// Recursively process the configuration class and its superclass hierarchy.
SourceClass sourceClass = asSourceClass(configClass, filter);
do {
sourceClass = doProcessConfigurationClass(configClass, sourceClass, filter);
}
while (sourceClass != null);
this.configurationClasses.put(configClass, configClass);
}


private SourceClass doProcessConfigurationClass(ConfigurationClass configClass, SourceClass sourceClass) throws IOException {
processMemberClasses(configClass, sourceClass);
processPropertySources(sourceClass);
processComponentScan(sourceClass);
processImports(configClass, sourceClass);
processImportSource(configClass, sourceClass);
processInterfaces(configClass, sourceClass);
processSuperclass(configClass, sourceClass);
return null;
}


doProcessConfigurationClass是伪代码, 下面具体展开介绍

9.4.3.1 @ComponentScan

@ComponentScan 是复合注解@SpringBootApplication的组成部分,
@ComponentScan对应XML配置形式中的元素,可以通过basePackages等属性来细粒度地定制@ComponentScan自动扫描的范围,如果不指定,则默认Spring框架实现会从声明@ComponentScan所在类的package进行扫描。

@ComponentScan扫描的包括@Component@Service@Repository@Controller

这段逻辑处理后,一个项目中定义的各种业务bean, 都会被解析到形成configClass

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
// Process any @ComponentScan annotations
Set<AnnotationAttributes> componentScans = AnnotationConfigUtils.attributesForRepeatable(
sourceClass.getMetadata(), ComponentScans.class, ComponentScan.class);
if (!componentScans.isEmpty() &&
!this.conditionEvaluator.shouldSkip(sourceClass.getMetadata(), ConfigurationPhase.REGISTER_BEAN)) {
for (AnnotationAttributes componentScan : componentScans) {
// The config class is annotated with @ComponentScan -> perform the scan immediately
Set<BeanDefinitionHolder> scannedBeanDefinitions =
this.componentScanParser.parse(componentScan, sourceClass.getMetadata().getClassName());
// Check the set of scanned definitions for any further config classes and parse recursively if needed
for (BeanDefinitionHolder holder : scannedBeanDefinitions) {
BeanDefinition bdCand = holder.getBeanDefinition().getOriginatingBeanDefinition();
if (bdCand == null) {
bdCand = holder.getBeanDefinition();
}
if (ConfigurationClassUtils.checkConfigurationClassCandidate(bdCand, this.metadataReaderFactory)) {
parse(bdCand.getBeanClassName(), holder.getBeanName());
}
}
}
}

这里会递归调用parse,处理每个解析的业务bean 定义

9.4.3.2 @Import

1
2
// Process any @Import annotations  
processImports(configClass, sourceClass, getImports(sourceClass), filter, true);
  • getImports 从sourceClass中找出@Import
  • processImports 方法处理 @Import 注解,导入配置类或特定的配置选择器(如 ImportSelectorImportBeanDefinitionRegistrar)。

一般来讲,一个SpringBoot项目的启动类如果配置如下

1
2
3
@SpringBootApplication  
@MapperScan("com.example.codingInAction.mapper")
public class CodingInActionApplication {}

那么可以找到以下3个通过@Import注解导入的类

  1. AutoConfigurationImportSelector
  2. AutoConfigurationPackages.Registrar
  3. MapperScannerRegistrar
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
@Target(ElementType.TYPE)  
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
@AutoConfigurationPackage
@Import(AutoConfigurationImportSelector.class)
public @interface EnableAutoConfiguration {}



@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
@Import(AutoConfigurationPackages.Registrar.class)
public @interface AutoConfigurationPackage {}


@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
@Documented
@Import(MapperScannerRegistrar.class)
@Repeatable(MapperScans.class)
public @interface MapperScan {}
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
private void processImports(ConfigurationClass configClass, SourceClass currentSourceClass,
Collection<SourceClass> importCandidates, Predicate<String> exclusionFilter,
boolean checkForCircularImports) {
for (SourceClass candidate : importCandidates) {
if (candidate.isAssignable(ImportSelector.class)) {
Class<?> candidateClass = candidate.loadClass();
ImportSelector selector = ParserStrategyUtils.instantiateClass(candidateClass, ImportSelector.class,
this.environment, this.resourceLoader, this.registry);
if (selector instanceof DeferredImportSelector) {
this.deferredImportSelectorHandler.handle(configClass, (DeferredImportSelector) selector);
}
}else if (candidate.isAssignable(ImportBeanDefinitionRegistrar.class)) {
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);
}
}

}

这段代码处理了三种类型的候选类(candidate)在@Import注解中的情况:ImportSelectorImportBeanDefinitionRegistrar和普通的@Configuration类。

  1. 候选类是ImportSelector类型
    1. 如果ImportSelector对象是DeferredImportSelector的实例,则将其交给deferredImportSelectorHandler处理。
    2. 否则递归处理这些导入的类。
  2. 候选类是ImportBeanDefinitionRegistrar类型:通过ParserStrategyUtils.instantiateClass方法实例化ImportBeanDefinitionRegistrar对象。将该对象注册到configClass中,以便它可以注册额外的bean定义。
  3. 如果候选类既不是ImportSelector也不是ImportBeanDefinitionRegistrar类型,则将其视为普通的@Configuration类。递归处理该类

我们重点关注AutoConfigurationImportSelector,它和自动配置类的解析有关, 且它是一个DeferredImportSelector,所以会执行deferredImportSelectorHandler.handle逻辑

processImports逻辑中,就可以遇到
parse 执行完成后, 业务上注册的bean 其配置信息均已处理完成,接下来就可以处理自动配置类了

9.4.4 DeferredImportSelectorHandler

AutoConfigurationImportSelector,它和自动配置类的解析有关, 且它是一个DeferredImportSelector,所以会执行deferredImportSelectorHandler.handle先将其记录下来,等所有其他正常数据处理完成后再来处理AutoConfigurationImportSelector

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
class ConfigurationClassParser {

private class DeferredImportSelectorHandler {
public void process() {
List<DeferredImportSelectorHolder> deferredImports = this.deferredImportSelectors;
this.deferredImportSelectors = null;
try {
if (deferredImports != null) {
DeferredImportSelectorGroupingHandler handler = new DeferredImportSelectorGroupingHandler();
deferredImports.sort(DEFERRED_IMPORT_COMPARATOR);
deferredImports.forEach(handler::register);
handler.processGroupImports();
}
}
finally {
this.deferredImportSelectors = new ArrayList<>();
}
}
public void process() {
List<DeferredImportSelectorHolder> deferredImports = this.deferredImportSelectors;
this.deferredImportSelectors = null;
try {
if (deferredImports != null) {
DeferredImportSelectorGroupingHandler handler = new DeferredImportSelectorGroupingHandler();
deferredImports.sort(DEFERRED_IMPORT_COMPARATOR);
deferredImports.forEach(handler::register);
handler.processGroupImports();
}
}
finally {
this.deferredImportSelectors = new ArrayList<>();
}
}
}
}

9.4.4.1 handle

handle方法,用于处理ConfigurationClassDeferredImportSelector的配对。具体来说:

  • 如果当前没有DeferredImportSelectorHolder,则立即处理新的延迟导入选择器。
  • 如果已有未处理的DeferredImportSelectorHolder,则将新的延迟导入选择器添加到列表中,以便稍后批量处理

DeferredImportSelectorHolder:一个持有ConfigurationClassDeferredImportSelector的配对类。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
class ConfigurationClassParser {
private static class DeferredImportSelectorHolder {

private final ConfigurationClass configurationClass;

private final DeferredImportSelector importSelector;

public DeferredImportSelectorHolder(ConfigurationClass configClass, DeferredImportSelector selector) {
this.configurationClass = configClass;
this.importSelector = selector;
}

public ConfigurationClass getConfigurationClass() {
return this.configurationClass;
}

public DeferredImportSelector getImportSelector() {
return this.importSelector;
}
}
}

9.4.4.2 process

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
class ConfigurationClassParser {	
public void parse(Set<BeanDefinitionHolder> configCandidates) {
for (BeanDefinitionHolder holder : configCandidates) {
BeanDefinition bd = holder.getBeanDefinition();
try {
if (bd instanceof AnnotatedBeanDefinition) {
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);
}
}
this.deferredImportSelectorHandler.process();
}
}

process 方法会在parse 结束后, 才执行deferredImportSelectorHandler.process逻辑, 符合它延迟执行的特性。下面来具体看下DeferredImportSelector 是如何解析自动配置类信息的

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
class ConfigurationClassParser {
private class DeferredImportSelectorHandler {
public void process() {
List<DeferredImportSelectorHolder> deferredImports = this.deferredImportSelectors;
this.deferredImportSelectors = null;
try {
if (deferredImports != null) {
DeferredImportSelectorGroupingHandler handler = new DeferredImportSelectorGroupingHandler();
deferredImports.sort(DEFERRED_IMPORT_COMPARATOR);
deferredImports.forEach(handler::register);
handler.processGroupImports();
}
}
finally {
this.deferredImportSelectors = new ArrayList<>();
}
}
}

private class DeferredImportSelectorGroupingHandler{
public void processGroupImports() {
for (DeferredImportSelectorGrouping grouping : this.groupings.values()) {
Predicate<String> exclusionFilter = grouping.getCandidateFilter();
grouping.getImports().forEach(entry -> {
ConfigurationClass configurationClass = this.configurationClasses.get(entry.getMetadata());
try {
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);
}
});
}
}
}
}

register

先进入register, 将AutoConfigurationImportSelector这个DeferredImportSelector 添加到configurationClasses这个map h中,前面经过parse 阶段解析出业务bean 信息都在map 中

getImports

在这里能够看到getImports,最终调用的的是SpringFactoriesLoader.loadFactoryNames, 这个方法SpringApplication初始化时已经执行读取过所有的META-INF/spring.factories文件,所以这里会直接使用cache 里面的数据,不会重复读取META-INF/spring.factories文件了。

从下图可以看到AutoConfigurationEntry存储了自动配置类的信息

processImports

拿到自动配置类信息后,就可以进行解析了,

processImports在9.3.5.2 节中讲过有3种逻辑

  1. 候选类是ImportSelector类型
    1. 如果ImportSelector对象是DeferredImportSelector的实例,则将其交给deferredImportSelectorHandler处理。
    2. 否则递归处理这些导入的类。
  2. 候选类是ImportBeanDefinitionRegistrar类型:通过ParserStrategyUtils.instantiateClass方法实例化ImportBeanDefinitionRegistrar对象。将该对象注册到configClass中,以便它可以注册额外的bean定义。
  3. 如果候选类既不是ImportSelector也不是ImportBeanDefinitionRegistrar类型,则将其视为普通的@Configuration类,执行processConfigurationClass递归处理该类

针对自动配置类会走到第3个逻辑, 以MybatisAutoConfiguration为例,解析该自动配置类会处理其用@Bean标注的2个bean

9.4.5 loadBeanDefinitions(configClasses)

parse 工作完成后,就可以loadBeanDefinitions 到BeanFactory中了

1
2
3
4
5
6
7
8
class ConfigurationClassBeanDefinitionReader {
public void loadBeanDefinitions(Set<ConfigurationClass> configurationModel) {
TrackedConditionEvaluator trackedConditionEvaluator = new TrackedConditionEvaluator();
for (ConfigurationClass configClass : configurationModel) {
loadBeanDefinitionsForConfigurationClass(configClass, trackedConditionEvaluator);
}
}
}

9.5 postProcessBeanFactory

以上注解解析+BeanDefinition 注册都是ConfigurationClassPostProcessor中重写的BeanDefinitionRegistryPostProcessor.postProcessBeanDefinitionRegistry 中的逻辑

现在来看ConfigurationClassPostProcessor中重写的BeanFactoryPostProcessor.postProcessBeanFactory

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
public class ConfigurationClassPostProcessor implements BeanDefinitionRegistryPostProcessor,
PriorityOrdered, ResourceLoaderAware, BeanClassLoaderAware, EnvironmentAware {
@Override
public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) {
int factoryId = System.identityHashCode(beanFactory);
if (this.factoriesPostProcessed.contains(factoryId)) {
throw new IllegalStateException(
"postProcessBeanFactory already called on this post-processor against " + beanFactory);
}
this.factoriesPostProcessed.add(factoryId);
if (!this.registriesPostProcessed.contains(factoryId)) {
// BeanDefinitionRegistryPostProcessor hook apparently not supported...
// Simply call processConfigurationClasses lazily at this point then.
processConfigBeanDefinitions((BeanDefinitionRegistry) beanFactory);
}

enhanceConfigurationClasses(beanFactory);
beanFactory.addBeanPostProcessor(new ImportAwareBeanPostProcessor(beanFactory));
}
}

这行代码最重要的逻辑是 enhanceConfigurationClasses 方法,它生成 @Configuration 类的 CGLIB 代理,以确保 @Bean 方法的正确性和单例性。代理类会覆盖 @Bean 方法,并在需要时调用 Spring 容器以获取已经创建的单例 bean。
为什么要给@Configuration 类 生成代理对象

  • Spring 容器中的每个 bean 默认是单例的,即使 @Bean 方法被多次调用,也应返回相同的实例。
  • 如果直接调用 @Bean 方法,每次调用都会创建一个新的实例,违反单例模式。

关于CGLIB 动态代理对象的生成, 可阅读查看Mybaits 通过自动配置与SpringBoot 集成的文章

10.自动配置类的的实例化

至此,整个项目中所有定义的bean,不论是SpringBoot 框架的自动配置类,,还是业务代码中手动配置的, 所有bean的BeanDefinition 全部注册完成。
普通业务bean得实例化过程我们已经非常熟悉了, 这里我们以Mybatis 自动配置类也是用同样的getBean流程完成实例化,具体实例化流程可以点击阅读Spring 集成 Mybatis

11 自动配置实现总结

自动配置类是如何从配置文件中的一行文字变成Spring 容器中可实际发挥作用的实例bean

11.1 加载自动配置类名称

自动配置类的名称在SpringApplication 实例化的过程中会完成加载工作。
具体的加载由SpringFactoriesLoader.loadFactoryNames读取所有META-INF/spring.factories文件,将文件中的信息用MultiValueMap存储,同时加载后的信息会缓存下来供后续使用,防止重复加载。
同时在这个过程中有SharedMetadataReaderFactoryContextInitializer添加到了ApplicationContext 中进行管理, 当后续执行其initialize时会
注册ConfigurationClassPostProcessor这个BeanPostFactoryProcessor

11.2 注册自动配置类BeanDefinition

所有的自动配置类如果想成为实例bean, 要在Spring 容器BeanFactory中先有BeanDefinition , 自动配置类BeanDefinition的注册由ConfigurationClassPostProcessor 完成。

ConfigurationClassPostProcessor 作为BeanPostFactoryProcessor, 其作用时机是invokeBeanFactoryPostProcessors.

ConfigurationClassPostProcessor 的职责 主要有两个

  1. @Configuration及其相关注解,解析成BeanDefinition
    1. 具体解析是有
    2. 再具体一点其实是由完成的
      3.
  2. 将解析得到的 BeanDefinition 注册到 BeanFactory 中。

@Configuration及其相关注解,解析成BeanDefinition实际是由ConfigurationClassParser 完成的

  1. ConfigurationClassParser 通过对@Import注解的处理,解析出AutoConfigurationImportSelector
  2. AutoConfigurationImportSelector才是最终负责自动配置类解析的工具, 因为它是DeferredImportSelector,所以AutoConfigurationImportSelector会先通过反射实例化然后记录下来,
  3. 等其他bean parse 工作完成后,再把AutoConfigurationImportSelector找出来处理自动配置类,将@Bean 标注的方法解析成BeanDefinition
  4. 当所有bean, 包括业务代码定义的bean 和自动配置类涉及到的bean, 全部注册到Spring容器BeanFactory 中

11.3 自动配置类的的实例化

根据BeanDefinition 实例化自动配置类。自动配置类有了bean definition 后, 就可以通过getBean流程被实例成bean, 即getBean