Spring Boot 自动配置的原理是什么?
简化版
Spring Boot 启动时,@SpringBootApplication 里的 @EnableAutoConfiguration 会加载一大批候选自动配置类,每个配置类用 @ConditionalOnXxx 条件注解判断「当前环境该不该生效」——比如类路径有没有某个 jar、容器里有没有某个 Bean。条件满足才注册对应的默认 Bean。核心是:从候选配置中按条件装配合理默认值,并在约定的条件范围内允许用户配置替换默认值。
详细版
触发入口:@SpringBootApplication = @SpringBootConfiguration + @ComponentScan + @EnableAutoConfiguration。其中 @EnableAutoConfiguration 是自动配置的开关。
加载候选类:它通过 @Import(AutoConfigurationImportSelector.class),去读各个 starter 的 META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports 文件(Spring Boot 2.7 前是 spring.factories),拿到一大串候选自动配置类的全限定名。
条件筛选:每个自动配置类头上挂着条件注解,决定它是否真正生效:
@ConditionalOnClass:类路径存在某个类才生效(如引了spring-boot-starter-data-redis,RedisAutoConfiguration才激活);@ConditionalOnMissingBean:容器里没有你自定义的同类型 Bean 时才用默认的(保证「用户配置优先」);@ConditionalOnProperty:某个配置属性满足条件才生效;- 还有
@ConditionalOnWebApplication等。
用户优先:@ConditionalOnMissingBean 是常见退让机制——当它检查的名称、类型和搜索范围命中用户 Bean 时,默认 Bean 不再注册;是否退让必须以具体条件声明为准。
完整版教学
一、自动配置解决什么:约定优于配置
Spring 时代配一个数据源要写一堆 XML/JavaConfig。Spring Boot 的理念是约定优于配置(Convention over Configuration):绝大多数项目的配置都长得差不多,那就由框架提供一套「合理的默认」,你只在需要时覆盖少量配置即可。
自动配置就是这套「合理默认」的实现机制:引入一个 starter(比如 web),它就自动帮你配好 Tomcat、DispatcherServlet、JSON 转换器等一整套,你几乎零配置就能跑起来。这就是 Spring Boot「开箱即用」的来源。
二、三步串起整个原理
面试答这题,能把这三步讲清就到位了:
@EnableAutoConfiguration开启 → 通过AutoConfigurationImportSelector加载META-INF/.../AutoConfiguration.imports(或spring.factories)里登记的所有候选自动配置类;- 条件注解筛选 → 每个候选类用
@ConditionalOnXxx判断当前环境,不满足的直接跳过(比如没引 Redis,Redis 相关配置就不加载); - 注册默认 Bean → 通过的配置类里,用
@Bean+@ConditionalOnMissingBean注册默认组件,但让位于用户自定义。
记忆点:「加载候选 → 条件过滤 → 用户优先」 三步走。
三、为什么是「有条件的」——@Conditional 家族
自动配置不是无脑把几百个 Bean 全塞进容器,否则又慢又冲突。关键在条件化:
@Configuration
@ConditionalOnClass(RedisOperations.class) // 类路径有 Redis 依赖才生效
@EnableConfigurationProperties(RedisProperties.class)
class RedisAutoConfiguration {
@Bean
@ConditionalOnMissingBean(name = "redisTemplate") // 你没定义才用默认
RedisTemplate<Object,Object> redisTemplate(...) { ... }
}
@ConditionalOnClass(RedisOperations.class) 意味着:只有你的项目真的引入了 Redis 依赖,这个配置才激活。所以自动配置的实际生效集会受到最终 classpath 强烈影响;Starter 是常见依赖入口,但单独引入相关库也可能满足类条件,属性、Bean 和应用类型等其他条件仍会继续筛选。
四、starter 和自动配置的关系
- starter(如
spring-boot-starter-web):本质是一个「依赖聚合包」,帮你一次性引入某功能需要的所有 jar; - 自动配置:这些 jar 里带着自动配置类和
.imports登记文件,被引入后@EnableAutoConfiguration就能发现并按条件激活它们。
两者配合:starter 负责「把依赖带进来」,自动配置负责「把 Bean 配好」。想自定义 starter,也是这个套路:写自动配置类 + 在 .imports 里登记。
五、候选很多为什么启动仍可控
候选自动配置类可能有数百个,但“候选”不等于“创建同样数量的 Bean”。类条件可在解析阶段快速排除无关配置,自动配置元数据还能帮助提前过滤;真正匹配的配置才继续评估 Bean、属性和 Web 类型等条件。假设有 300 个候选,其中 240 个因类路径条件不满足被排除,剩余 60 个也只会按各自条件注册必要 Bean。
AutoConfiguration.imports
↓ 读取候选
class / property / web 条件过滤
↓
匹配的 @AutoConfiguration
↓ @ConditionalOnMissingBean 等
注册默认 Bean,或因用户配置而退让
自动配置顺序只影响 BeanDefinition 的注册先后,不等于 Bean 实例创建顺序;实例何时创建仍由依赖关系、作用域、lazy 与 @DependsOn 等决定。需要先后关系时可声明 auto-configuration 的 before/after,而不应依赖 imports 文件的偶然排列。
@SpringBootApplication(exclude = DataSourceAutoConfiguration.class)
class Application {}
排除配置适合明确知道某项默认能力永远不需要的场景。若只是想替换某个默认 Bean,通常优先提供用户 Bean 让条件退让;直接排除整个自动配置可能连带失去同一配置类提供的其他基础设施。
| 排查现象 | 首先检查 | 常见原因 |
|---|---|---|
| 自动配置未出现 | 候选是否被发现 | imports 未登记或被 exclude |
| 配置出现但未匹配 | ConditionEvaluationReport | 缺类、属性值不符、应用类型不符 |
| 默认 Bean 未创建 | Bean 条件 | 用户已有同名或同类型 Bean |
| 创建后行为不对 | 最终属性与依赖版本 | 配置覆盖或版本组合不兼容 |
排障钩子:自动配置问题按“有没有候选 → 条件是否匹配 → Bean 是否退让 → 属性是否正确”逐层查,不要只盯着一个注解。
六、常见误区与追问
- 误区:自动配置会无条件实例化全部候选类里的 Bean。 候选必须通过类路径、属性、Bean、Web 类型等条件,且注册 Bean 后还受正常生命周期规则控制。
- 误区:@ConditionalOnMissingBean 保证任何用户配置都优先。 它只按声明的名称、类型或搜索范围判断,条件写得不合适仍可能冲突或产生两个 Bean。
- 误区:Starter 和自动配置是同一个东西。 Starter 聚合依赖,自动配置根据环境注册 Bean;二者常配套但职责不同。
- 追问:怎样查看某项自动配置为什么没生效? 使用
--debug或相应调试日志查看 ConditionEvaluationReport,区分 positive matches、negative matches 和 exclusions。 - 追问:如何彻底排除某个自动配置? 可使用注解的 exclude/excludeName,或通过
spring.autoconfigure.exclude配置,具体类名应以目标 Boot 版本为准。 - 追问:为什么自定义自动配置不应依赖组件扫描发现? 官方约定由 AutoConfiguration.imports 明确登记并用精确 Import 组织组件,避免污染使用者扫描边界。
七、加强记忆
自动配置的原理是:@EnableAutoConfiguration 加载 .imports(旧版 spring.factories)里登记的候选配置类,每个类用 @ConditionalOnClass/@ConditionalOnMissingBean 等条件注解判断是否生效,满足具体条件才注册默认 Bean;其中很多配置使用 @ConditionalOnMissingBean 在声明的匹配范围内为用户 Bean 退让。本质是「约定优于配置」的按需装配。