自动配置原理
Spring Boot 自动配置原理详解:从注解到源码的全链路拆解
Spring Boot 的 “自动配置” 是其核心特性之一,本质是通过 “约定大于配置” 的思想,在启动时自动加载符合条件的配置类,减少手动 XML/Java 配置。本文基于 Spring Boot 2.x 版本,从 “入口注解→核心选择器→配置加载→条件过滤→上下文触发” 五个维度,彻底拆解自动配置的底层逻辑,帮你理解 “为什么引入依赖就能自动生效”。
自动配置的入口:@SpringBootApplication 组合注解
自动配置的起点是启动类上的 @SpringBootApplication 注解 —— 它并非单一注解,而是 @Configuration + @EnableAutoConfiguration + @ComponentScan 的组合,其中 @EnableAutoConfiguration 是自动配置的 “总开关”。
1. @SpringBootApplication 源码拆解
// 1. 标识为 Spring Boot 配置类(本质是 @Configuration 的语义化封装)
// 2. 自动配置核心:开启并触发自动配置逻辑
// 3. 组件扫描:扫描当前包及其子包的 @Component/@Controller/@Service 等 Bean
public 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. 导入自动配置类选择器:AutoConfigurationImportSelector
// 2. 自动配置包扫描(默认是启动类所在的包)
public 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 容器。
我们拆解其核心方法调用链路:selectImports → getAutoConfigurationEntry → filter → getCandidateConfigurations
步骤 1:判断自动配置是否开启(selectImports 方法)
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
该文件存储了 “自动配置类的过滤条件”,例如:
# 表示 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 方法)
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 文件中配置的自动配置类:
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)提供,部分内容如下:
# 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 方法完成:
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 解析配置类时触发。
核心调用链路:
- 启动 Spring 上下文:
SpringApplication.run()→refreshContext(context)→AbstractApplicationContext#refresh(); - 执行 BeanFactory 后置处理器:
invokeBeanFactoryPostProcessors(beanFactory)→ 执行ConfigurationClassPostProcessor(处理@Configuration注解的类); - 解析配置类:
ConfigurationClassPostProcessor#processConfigBeanDefinitions()→ 解析启动类(标注@Configuration); - 处理延迟导入选择器:
ConfigurationClassParser#parse()→ 触发DeferredImportSelectorHandler#process()(AutoConfigurationImportSelector实现了DeferredImportSelector); - 加载自动配置类:
AutoConfigurationGroup#process()→ 调用getAutoConfigurationEntry()获取符合条件的自动配置类,最终导入 Spring 容器。
关键纠正:不是 selectImports,而是 AutoConfigurationGroup
“实际通过 AutoConfigurationGroup 的 process 方法调用 getAutoConfigurationEntry,而非 selectImports”,这是 Spring Boot 2.x 的关键改进:
AutoConfigurationImportSelector实现了DeferredImportSelector(延迟导入选择器),其处理会延迟到配置类解析的后期;- 延迟处理的核心是
AutoConfigurationGroup(AutoConfigurationImportSelector的静态内部类),通过process方法批量处理自动配置类,避免早期处理导致的依赖问题。
自动配置的最终结果:按需注入配置类
经过上述步骤后,符合条件的自动配置类(如 WebMvcAutoConfiguration、DataSourceAutoConfiguration)会被导入 Spring 容器,并注册对应的 Bean(如 DispatcherServlet、DataSource),最终实现 “引入依赖即自动配置”。
示例:Web 应用的自动配置
- 引入
spring-boot-starter-web依赖 → 依赖包含spring-webmvc、tomcat-embed-core等; - 启动应用 →
@EnableAutoConfiguration触发AutoConfigurationImportSelector; - 加载
spring.factories中的WebMvcAutoConfiguration、TomcatAutoConfiguration; - 过滤条件满足(存在
DispatcherServlet类、是 Web 应用)→ 两个配置类生效; - 自动配置类注册
DispatcherServlet、Tomcat等 Bean → 应用可直接处理 HTTP 请求,无需手动配置。
总结:自动配置的核心逻辑
Spring Boot 自动配置的本质是 “约定 + 筛选”,可概括为 5 个核心步骤:
- 入口触发:
@SpringBootApplication包含@EnableAutoConfiguration,开启自动配置; - 导入选择器:
@Import(AutoConfigurationImportSelector.class),由选择器执行加载逻辑; - 加载候选类:通过
SpringFactoriesLoader读取META-INF/spring.factories中的候选自动配置类; - 条件筛选:根据
spring-autoconfigure-metadata.properties和@ConditionalOnxxx注解,过滤不符合条件的类; - 注入容器:符合条件的自动配置类被导入 Spring 容器,注册对应 Bean,完成自动配置