0%

自动配置原理

Spring Boot 自动配置原理详解:从注解到源码的全链路拆解

Spring Boot 的 “自动配置” 是其核心特性之一,本质是通过 “约定大于配置” 的思想,在启动时自动加载符合条件的配置类,减少手动 XML/Java 配置。本文基于 Spring Boot 2.x 版本,从 “入口注解→核心选择器→配置加载→条件过滤→上下文触发” 五个维度,彻底拆解自动配置的底层逻辑,帮你理解 “为什么引入依赖就能自动生效”。

自动配置的入口:@SpringBootApplication 组合注解

自动配置的起点是启动类上的 @SpringBootApplication 注解 —— 它并非单一注解,而是 @Configuration + @EnableAutoConfiguration + @ComponentScan 的组合,其中 @EnableAutoConfiguration 是自动配置的 “总开关”。

1. @SpringBootApplication 源码拆解

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
// 1. 标识为 Spring Boot 配置类(本质是 @Configuration 的语义化封装)
@SpringBootConfiguration
// 2. 自动配置核心:开启并触发自动配置逻辑
@EnableAutoConfiguration
// 3. 组件扫描:扫描当前包及其子包的 @Component/@Controller/@Service 等 Bean
@ComponentScan(excludeFilters = {
@Filter(type = FilterType.CUSTOM, classes = TypeExcludeFilter.class),
@Filter(type = FilterType.CUSTOM, classes = AutoConfigurationExcludeFilter.class)
})
public @interface SpringBootApplication {
// 排除指定的自动配置类(如 exclude = DataSourceAutoConfiguration.class)
Class<?>[] exclude() default {};
String[] excludeName() default {};
}
三个子注解的核心作用:
注解 核心功能 对自动配置的意义
@SpringBootConfiguration 等同于 @Configuration,允许在类中用 @Bean 注册 Bean 提供自动配置类的 “配置类身份”
@EnableAutoConfiguration 开启自动配置,导入符合条件的自动配置类 自动配置的 “总开关”,核心中的核心
@ComponentScan 扫描并注册组件 Bean 确保用户自定义的 Bean 能被加载,与自动配置 Bean 协同

自动配置的核心:@EnableAutoConfiguration 注解

@EnableAutoConfiguration 是触发自动配置的关键,其核心逻辑是通过 @Import(AutoConfigurationImportSelector.class) 导入一个 “选择器”,由该选择器加载并筛选自动配置类。

1. @EnableAutoConfiguration 源码解析

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
// 1. 导入自动配置类选择器:AutoConfigurationImportSelector
@Import(AutoConfigurationImportSelector.class)
// 2. 自动配置包扫描(默认是启动类所在的包)
@AutoConfigurationPackage
public @interface EnableAutoConfiguration {
// 开关:通过配置 spring.boot.enableautoconfiguration=false 关闭自动配置
String ENABLED_OVERRIDE_PROPERTY = "spring.boot.enableautoconfiguration";

// 排除不需要的自动配置类(如数据源自动配置)
Class<?>[] exclude() default {};
String[] excludeName() default {};
}
两个关键细节:
  • @Import(AutoConfigurationImportSelector.class):这是自动配置的 “引擎”——AutoConfigurationImportSelector 负责从指定位置加载自动配置类,并过滤掉不符合条件的类;
  • @AutoConfigurationPackage:通过 @Import(AutoConfigurationPackages.Registrar.class) 将启动类所在的包注册为 “自动配置包”,确保该包下的组件能被扫描(补充 @ComponentScan 的扫描范围)。

自动配置类的加载:AutoConfigurationImportSelector 的工作机制

AutoConfigurationImportSelector 是自动配置的 “执行者”,其核心任务是:加载候选自动配置类→过滤不符合条件的类→最终导入符合条件的类到 Spring 容器

我们拆解其核心方法调用链路:
selectImportsgetAutoConfigurationEntryfiltergetCandidateConfigurations

步骤 1:判断自动配置是否开启(selectImports 方法)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
@Override
public String[] selectImports(AnnotationMetadata annotationMetadata) {
// 1. 检查开关:若 spring.boot.enableautoconfiguration=false,不导入任何类
if (!isEnabled(annotationMetadata)) {
return NO_IMPORTS;
}
// 2. 加载自动配置的“过滤元数据”(来自 META-INF/spring-autoconfigure-metadata.properties)
AutoConfigurationMetadata autoConfigurationMetadata = AutoConfigurationMetadataLoader
.loadMetadata(this.beanClassLoader);
// 3. 核心:获取符合条件的自动配置类(关键方法)
AutoConfigurationEntry autoConfigurationEntry = getAutoConfigurationEntry(autoConfigurationMetadata,
annotationMetadata);
// 4. 返回最终要导入的自动配置类全类名数组
return StringUtils.toStringArray(autoConfigurationEntry.getConfigurations());
}
关键文件:spring-autoconfigure-metadata.properties

该文件存储了 “自动配置类的过滤条件”,例如:

1
2
3
4
# 表示 DataSourceAutoConfiguration 需满足“存在 DataSource 类”才生效
org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration.ConditionalOnClass=javax.sql.DataSource
# 表示 WebMvcAutoConfiguration 需满足“是 Web 应用”才生效
org.springframework.boot.autoconfigure.web.servlet.WebMvcAutoConfiguration.ConditionalOnWebApplication=SERVLET

这些条件会在后续过滤步骤中使用,确保自动配置类 “按需生效”。

步骤 2:获取候选自动配置类(getAutoConfigurationEntry 方法)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
protected AutoConfigurationEntry getAutoConfigurationEntry(AutoConfigurationMetadata autoConfigurationMetadata,
AnnotationMetadata annotationMetadata) {
if (!isEnabled(annotationMetadata)) {
return EMPTY_ENTRY;
}
// 1. 获取 @EnableAutoConfiguration 注解的属性(如 exclude 排除的类)
AnnotationAttributes attributes = getAttributes(annotationMetadata);
// 2. 核心:加载“候选自动配置类”(从 META-INF/spring.factories 中读取)
List<String> configurations = getCandidateConfigurations(annotationMetadata, attributes);
// 3. 去重:避免重复导入同一自动配置类
configurations = removeDuplicates(configurations);
// 4. 排除:移除 @EnableAutoConfiguration 中 exclude 的类
Set<String> exclusions = getExclusions(annotationMetadata, attributes);
checkExcludedClasses(configurations, exclusions);
configurations.removeAll(exclusions);
// 5. 过滤:根据 spring-autoconfigure-metadata.properties 的条件筛选
configurations = filter(configurations, autoConfigurationMetadata);
// 6. 发布事件:通知自动配置类已导入(扩展用)
fireAutoConfigurationImportEvents(configurations, exclusions);
// 7. 返回最终符合条件的自动配置类
return new AutoConfigurationEntry(configurations, exclusions);
}
核心方法:getCandidateConfigurations(加载候选类)

该方法通过 SpringFactoriesLoader 加载 META-INF/spring.factories 文件中配置的自动配置类:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
protected List<String> getCandidateConfigurations(AnnotationMetadata metadata, AnnotationAttributes attributes) {
// 1. 调用 SpringFactoriesLoader,按 key=EnableAutoConfiguration 读取配置
List<String> configurations = SpringFactoriesLoader.loadFactoryNames(
getSpringFactoriesLoaderFactoryClass(), getBeanClassLoader());
// 2. 断言:若没有加载到配置,抛出异常(通常是依赖缺失)
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;
}

// 固定 key:org.springframework.boot.autoconfigure.EnableAutoConfiguration
protected Class<?> getSpringFactoriesLoaderFactoryClass() {
return EnableAutoConfiguration.class;
}
关键文件:META-INF/spring.factories

该文件是 Spring Boot 自动配置的 “配置清单”,由 Spring Boot 自动配置模块(spring-boot-autoconfigure)提供,部分内容如下:

1
2
3
4
5
6
7
# EnableAutoConfiguration 对应的自动配置类列表
org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration,\
org.springframework.boot.autoconfigure.web.servlet.WebMvcAutoConfiguration,\
org.springframework.boot.autoconfigure.redis.RedisAutoConfiguration,\
org.springframework.boot.autoconfigure.tomcat.TomcatAutoConfiguration,\
# ... 其他约 100+ 个自动配置类

这些类就是 “候选自动配置类”,后续会通过过滤步骤筛选出符合当前环境的类。

步骤 3:过滤不符合条件的自动配置类(filter 方法)

候选自动配置类(约 100+ 个)并非全部生效,需通过 @ConditionalOnxxx 注解(如 @ConditionalOnClass@ConditionalOnBean)筛选,这一步由 filter 方法完成:

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
private List<String> filter(List<String> configurations, AutoConfigurationMetadata autoConfigurationMetadata) {
long startTime = System.nanoTime();
String[] candidates = StringUtils.toStringArray(configurations);
boolean[] skip = new boolean[candidates.length];
boolean skipped = false;

// 1. 获取核心过滤器:OnClassCondition(类存在条件)、OnBeanCondition(Bean存在条件)、OnWebApplicationCondition(Web应用条件)
for (AutoConfigurationImportFilter filter : getAutoConfigurationImportFilters()) {
invokeAwareMethods(filter); // 注入 BeanClassLoader、BeanFactory 等
// 2. 执行过滤:判断每个候选类是否满足条件
boolean[] match = filter.match(candidates, autoConfigurationMetadata);
for (int i = 0; i < match.length; i++) {
if (!match[i]) {
skip[i] = true; // 不满足条件,标记为“跳过”
candidates[i] = null;
skipped = true;
}
}
}

// 3. 收集符合条件的类(未被标记为 skip 的)
if (!skipped) {
return configurations;
}
List<String> result = new ArrayList<>(candidates.length);
for (int i = 0; i < candidates.length; i++) {
if (!skip[i]) {
result.add(candidates[i]);
}
}
return new ArrayList<>(result);
}
过滤逻辑示例:
  • 若项目引入 spring-boot-starter-web 依赖,WebMvcAutoConfiguration 会因 “存在 DispatcherServlet 类”(@ConditionalOnClass)而生效;
  • 若项目未引入 spring-boot-starter-data-redis 依赖,RedisAutoConfiguration 会因 “不存在 RedisTemplate 类” 而被过滤,不生效;
  • 若项目是非 Web 应用,TomcatAutoConfiguration 会因 “不是 Web 应用”(@ConditionalOnWebApplication)而被过滤。

自动配置的触发时机:上下文刷新阶段

“自动配置在上下文初始化时触发”,具体是在 AbstractApplicationContext#refresh() 方法的 invokeBeanFactoryPostProcessors 步骤,由 ConfigurationClassPostProcessor 解析配置类时触发。

核心调用链路:

  1. 启动 Spring 上下文SpringApplication.run()refreshContext(context)AbstractApplicationContext#refresh()
  2. 执行 BeanFactory 后置处理器invokeBeanFactoryPostProcessors(beanFactory) → 执行 ConfigurationClassPostProcessor(处理 @Configuration 注解的类);
  3. 解析配置类ConfigurationClassPostProcessor#processConfigBeanDefinitions() → 解析启动类(标注 @Configuration);
  4. 处理延迟导入选择器ConfigurationClassParser#parse() → 触发 DeferredImportSelectorHandler#process()AutoConfigurationImportSelector 实现了 DeferredImportSelector);
  5. 加载自动配置类AutoConfigurationGroup#process() → 调用 getAutoConfigurationEntry() 获取符合条件的自动配置类,最终导入 Spring 容器。
关键纠正:不是 selectImports,而是 AutoConfigurationGroup

“实际通过 AutoConfigurationGroupprocess 方法调用 getAutoConfigurationEntry,而非 selectImports”,这是 Spring Boot 2.x 的关键改进:

  • AutoConfigurationImportSelector 实现了 DeferredImportSelector(延迟导入选择器),其处理会延迟到配置类解析的后期;
  • 延迟处理的核心是 AutoConfigurationGroupAutoConfigurationImportSelector 的静态内部类),通过 process 方法批量处理自动配置类,避免早期处理导致的依赖问题。

自动配置的最终结果:按需注入配置类

经过上述步骤后,符合条件的自动配置类(如 WebMvcAutoConfigurationDataSourceAutoConfiguration)会被导入 Spring 容器,并注册对应的 Bean(如 DispatcherServletDataSource),最终实现 “引入依赖即自动配置”。

示例:Web 应用的自动配置

  1. 引入 spring-boot-starter-web 依赖 → 依赖包含 spring-webmvctomcat-embed-core 等;
  2. 启动应用 → @EnableAutoConfiguration 触发 AutoConfigurationImportSelector
  3. 加载 spring.factories 中的 WebMvcAutoConfigurationTomcatAutoConfiguration
  4. 过滤条件满足(存在 DispatcherServlet 类、是 Web 应用)→ 两个配置类生效;
  5. 自动配置类注册 DispatcherServletTomcat 等 Bean → 应用可直接处理 HTTP 请求,无需手动配置。

总结:自动配置的核心逻辑

Spring Boot 自动配置的本质是 “约定 + 筛选”,可概括为 5 个核心步骤:

  1. 入口触发@SpringBootApplication 包含 @EnableAutoConfiguration,开启自动配置;
  2. 导入选择器@Import(AutoConfigurationImportSelector.class),由选择器执行加载逻辑;
  3. 加载候选类:通过 SpringFactoriesLoader 读取 META-INF/spring.factories 中的候选自动配置类;
  4. 条件筛选:根据 spring-autoconfigure-metadata.properties@ConditionalOnxxx 注解,过滤不符合条件的类;
  5. 注入容器:符合条件的自动配置类被导入 Spring 容器,注册对应 Bean,完成自动配置

欢迎关注我的其它发布渠道