自动配置原理
本教程共 48 篇 · 第 6 篇 · 更新于 2026-08-13 · 约 4 分钟阅读
本节目标:搞懂 Spring Boot「零配置」的秘密——条件注解怎么工作、自动配置怎么加载、如何自定义与关闭自动配置。
自动配置:把配菜备齐的厨房
第一次用 Spring Boot,你只加了一个 spring-boot-starter-webmvc 依赖,什么都没配。启动后 Tomcat 起来了,JSON 能返回了。谁干的?自动配置(Auto-configuration)。
官方文档一句话点破:Spring Boot 根据 classpath 上的 jar 依赖,自动帮你配置 Spring 应用。比如 classpath 里有 H2 数据库驱动,你又没手动配数据源,Boot 就自动配一个内存数据库。
把自动配置想成点菜:你点了「Web」这道菜(Starter),厨房(Spring Boot)自动把配菜备齐——Tomcat、Jackson、Spring MVC,全给你端上来。
自动配置不是魔法。它由两块拼成:条件注解决定「配不配」,加载机制决定「怎么配」。
总开关:@EnableAutoConfiguration
自动配置默认关着。你要在一个 @Configuration 类上显式开启:
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
import org.springframework.context.annotation.Configuration;
@Configuration
@EnableAutoConfiguration
public class MyApplication {
}
实际项目里,你用的是 @SpringBootApplication。它内部就包含 @EnableAutoConfiguration(第 4 章讲过),主类一标,自动配置就开了。
Warning全项目只能有一个
@SpringBootApplication或@EnableAutoConfiguration。加在多个类上会出问题,官方建议只加在主配置类上。
条件注解:自动配置的投票器
每个自动配置类都是候选。装不装,由 @Conditional* 系列注解投票决定。这族注解是自动配置的灵魂,面试常考。
| 注解 | 生效条件 |
|---|---|
@ConditionalOnClass / @ConditionalOnMissingClass | classpath 里有 / 没有某个类 |
@ConditionalOnBean / @ConditionalOnMissingBean | 容器里已经 / 还没有某个 Bean |
@ConditionalOnProperty | 配置属性等于指定值 |
@ConditionalOnResource | 某个资源文件存在 |
@ConditionalOnWebApplication / @ConditionalOnNotWebApplication | 当前是不是 Web 应用 |
@ConditionalOnExpression | SpEL 表达式为 true |
@Conditional | 自定义条件类 |
@ConditionalOnClass 出场率最高。只有类存在,配置才生效:
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
import org.springframework.context.annotation.Configuration;
@Configuration(proxyBeanMethods = false)
@ConditionalOnClass(name = "com.mysql.cj.jdbc.Driver")
public class MySqlAutoConfiguration {
// classpath 里有 MySQL 驱动时,这个配置类才被加载
}
用 name 写全类名,类没在 classpath 上也不会编译报错,这是官方推荐写法。
@ConditionalOnProperty 按配置项开关。经典用法:同一个接口两个实现,靠一个属性切换。下面的例子摘自 mkyong 的开源示例:
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.stereotype.Service;
@Service
@ConditionalOnProperty(name = "app.feature.new", havingValue = "true")
public class RedisSessionService implements WebSessionService {
@Override
public String getUserData() {
return "Data from Redis...";
}
}
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.stereotype.Service;
@Service
@ConditionalOnProperty(name = "app.feature.new", havingValue = "false", matchIfMissing = true)
public class PostgreSessionService implements WebSessionService {
@Override
public String getUserData() {
return "Data from PostgreSQL Database";
}
}
application.properties 里写一行:
app.feature.new=true
属性为 true 时注册 Redis 实现;为 false 或缺失时,matchIfMissing = true 让 Postgre 实现兜底。写一个开关,两套逻辑,改配置就切换。
加载机制:谁在找自动配置类
条件注解只是「候选」。谁来收集候选?Spring Boot 启动时会扫描所有 jar 里的一个固定文件:
META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports
这个文件每行写一个自动配置类的全类名。Boot 把 classpath 上所有 jar 的这个文件读出来,汇总成候选列表,再逐个用条件注解评估。评估通过的,它的 @Bean 方法就被执行,Bean 进容器。
Note时间线:2.7 之前,自动配置注册在
META-INF/spring.factories;2.7 起引入上面的.imports文件,两者并存过渡;3.0 起只认.imports。看到旧教程写spring.factories,别照抄。
自动配置类本身用 @AutoConfiguration 标注。它相当于 @Configuration(proxyBeanMethods = false),还能用 after、before 指定顺序:
import org.springframework.boot.autoconfigure.AutoConfiguration;
import org.springframework.boot.jdbc.autoconfigure.DataSourceAutoConfiguration;
@AutoConfiguration(after = DataSourceAutoConfiguration.class)
public class MyAutoConfiguration {
}
顺序很重要。JPA 的自动配置,必须等数据源配好再跑。
还有一个配套注解:@AutoConfigurationPackage。它把主类所在包登记为「自动配置包」。JPA 实体、Spring Data 仓库的默认扫描范围,就是从这个包出发的。@EnableAutoConfiguration 会自动带上它,平时不用手写。
查账:谁生效了,为什么
自动配置看着像黑盒,其实能查账。启动时加 --debug:
mvn spring-boot:run -Dspring-boot.run.arguments=--debug
控制台会输出一份「条件评估报告」:每个自动配置类,生效(matched)还是没生效(not matched),为什么。没生效的原因写得很直白,比如「没找到某个类」「已有同名 Bean」。
排查「为什么我的配置没生效」,第一件事就是看这份报告。
关掉多余的自动配置
有的自动配置你不想要。比如项目不用数据库,启动却报数据源相关错误。用 exclude 关掉:
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.jdbc.autoconfigure.DataSourceAutoConfiguration;
@SpringBootApplication(exclude = DataSourceAutoConfiguration.class)
public class MyApplication {
}
类不在 classpath 时,用 excludeName 写全类名。也可以用配置属性,一处顶全局。注解里的 exclude 和属性的排除是叠加关系,按并集生效:
spring.autoconfigure.exclude=org.springframework.boot.jdbc.autoconfigure.DataSourceAutoConfiguration
Tip排除是「局部刹车」。自动配置本身很谦让——你一旦自己定义了
DataSourceBean,Boot 的默认数据源配置会自动退让,多数情况不用排除。
自定义自动配置:三步写自己的 Starter
理解了机制,就能写自己的自动配置。给一个「问候服务」做自动配置,三步走。
第一步,服务类和属性类。服务类提供业务,属性类让用户可配置:
package com.example.hello;
public class HelloService {
private final String prefix;
public HelloService(String prefix) {
this.prefix = prefix;
}
public String sayHello(String name) {
return prefix + "," + name;
}
}
package com.example.hello;
import org.springframework.boot.context.properties.ConfigurationProperties;
@ConfigurationProperties(prefix = "hello")
public class HelloProperties {
private String prefix = "你好";
public String getPrefix() {
return prefix;
}
public void setPrefix(String prefix) {
this.prefix = prefix;
}
}
第二步,自动配置类。条件齐上:类存在、属性允许、Bean 缺失才配:
package com.example.hello;
import org.springframework.boot.autoconfigure.AutoConfiguration;
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.context.annotation.Bean;
@AutoConfiguration
@ConditionalOnClass(HelloService.class)
@ConditionalOnProperty(prefix = "hello", name = "enabled", havingValue = "true", matchIfMissing = true)
@EnableConfigurationProperties(HelloProperties.class)
public class HelloAutoConfiguration {
@Bean
@ConditionalOnMissingBean
public HelloService helloService(HelloProperties properties) {
return new HelloService(properties.getPrefix());
}
}
第三步,注册。在 src/main/resources 下建文件:
META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports
内容一行:
com.example.hello.HelloAutoConfiguration
用户引入这个 jar 后,在 application.yml 里写:
hello:
prefix: "早上好"
HelloService Bean 就带着新前缀出现了。@ConditionalOnMissingBean 是关键——用户自己定义了 HelloService,你的自动配置就退让,不抢戏。这就是 Starter 的原理,第 8 章接着讲它的依赖体系。
小结
- 自动配置 = 条件注解(配不配)+ 加载机制(怎么配)。
@ConditionalOnMissingBean是「让位」机制,用户自定义优先。--debug看条件报告,exclude关多余配置。- 自定义自动配置:
@AutoConfiguration类 +.imports注册文件。