Spring Boot 自动配置原理
一、自动配置核心注解
@EnableAutoConfiguration
java
@AutoConfigurationPackage // 自动配置包
@Import(AutoConfigurationImportSelector.class)
public @interface EnableAutoConfiguration {
Class<?>[] exclude() default {};
String[] excludeName() default {};
}@AutoConfiguration
java
// 标记这是一个自动配置类
@AutoConfiguration
// 条件:类路径有 DataSource
@ConditionalOnClass(DataSource.class)
// 条件:没有手动配置 DataSource
@ConditionalOnMissingBean(DataSource.class)
public class DataSourceAutoConfiguration {
@Bean
public DataSource dataSource() {
// 自动配置数据源
return new HikariDataSource();
}
}二、自动配置流程
┌─────────────────────────────────────────────────────────────────┐
│ 自动配置完整流程 │
├─────────────────────────────────────────────────────────────────┤
│ │
│ SpringApplication.run() │
│ │ │
│ ▼ │
│ prepareContext() │
│ │ │
│ ▼ │
│ load邦元 (Bean Definitions) │
│ │ │
│ ├─ 主类 (@SpringBootApplication) │
│ └─ @Import(AutoConfigurationImportSelector) │
│ │
│ ▼ │
│ refreshContext() → invokeBeanFactoryProcessors() │
│ │ │
│ ▼ │
│ AutoConfigurationImportSelector.selectImports() │
│ │ │
│ ├─ 1. 获取 spring.factories 中的配置类 │
│ │ META-INF/spring.factories │
│ │ EnableAutoConfiguration = xxxAutoConfiguration │
│ │ │
│ ├─ 2. 过滤排除 │
│ │ @ConditionalOnClass │
│ │ @ConditionalOnMissingBean │
│ │ @ConditionalOnProperty │
│ │ │
│ └─ 3. 返回需要导入的配置类列表 │
│ │
│ ▼ │
│ ConfigurationClassPostProcessor 处理配置类 │
│ │ │
│ ├─ @Bean 注册为 Bean │
│ ├─ @Import 导入其他配置类 │
│ └─ @ComponentScan 扫描组件 │
│ │
│ ▼ │
│ 配置类中的 @Bean 被注册 │
│ │
└─────────────────────────────────────────────────────────────────┘三、@Conditional 条件装配
常用条件注解
| 注解 | 条件 |
|---|---|
| @ConditionalOnClass | 类路径存在某类时生效 |
| @ConditionalOnMissingClass | 类路径不存在某类时生效 |
| @ConditionalOnBean | 容器中存在某 Bean 时生效 |
| @ConditionalOnMissingBean | 容器中不存在某 Bean 时生效 |
| @ConditionalOnProperty | 配置属性满足条件时生效 |
| @ConditionalOnResource | 存在某资源时生效 |
| @ConditionalOnWebApplication | 是 Web 应用时生效 |
| @ConditionalOnNotWebApplication | 非 Web 应用时生效 |
@ConditionalOnClass
java
@Configuration
@AutoConfiguration
// 只有类路径存在 RedisOperations 时才加载
@ConditionalOnClass(RedisOperations.class)
public class RedisAutoConfiguration {
@Bean
@ConditionalOnMissingBean
public RedisTemplate<String, Object> redisTemplate() {
return new RedisTemplate<>();
}
}@ConditionalOnMissingBean
java
@Configuration
@AutoConfiguration
public class DataSourceAutoConfiguration {
@Bean
// 如果用户没有手动定义 DataSource,才使用自动配置
@ConditionalOnMissingBean(DataSource.class)
public DataSource dataSource() {
return new HikariDataSource();
}
}
// 用户可以覆盖
@Configuration
public class MyConfig {
@Bean
public DataSource dataSource() { // 优先级更高
return new DruidDataSource();
}
}@ConditionalOnProperty
java
@Configuration
@AutoConfiguration
public class CacheAutoConfiguration {
@Bean
// 配置 spring.cache.type=redis 时生效
@ConditionalOnProperty(
name = "spring.cache.type",
havingValue = "redis",
matchIfMissing = false // 默认为 false
)
public RedisCacheManager cacheManager() {
return new RedisCacheManager();
}
}
# application.yml
spring:
cache:
type: redis条件组合
java
@Configuration
@AutoConfiguration
// 多个条件同时满足
@ConditionalOnClass({RedisOperations.class, CacheManager.class})
@ConditionalOnBean(CacheManager.class)
@ConditionalOnProperty(
prefix = "spring.cache",
name = "type",
havingValue = "redis"
)
public class RedisCacheAutoConfiguration {
// ...
}自定义条件
java
// 1. 实现 Condition 接口
public class MyCondition implements Condition {
@Override
public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) {
// 自定义条件逻辑
return context.getEnvironment().containsProperty("my.feature.enabled");
}
}
// 2. 使用
@Bean
@Conditional(MyCondition.class)
public MyBean myBean() {
return new MyBean();
}
// 3. 自定义条件注解
@Target({ElementType.TYPE, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Conditional(MyCondition.class)
public @interface ConditionalOnMyFeature { }四、spring.factories 机制
文件位置与格式
META-INF/spring.factoriesproperties
# 格式:接口=实现类(多个用逗号分隔)
# 自动配置类
org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
com.example.autoconfig.MyAutoConfiguration,\
com.example.autoconfig.OtherAutoConfiguration
# 失败分析器
org.springframework.boot.autoconfigure.FailureAnalyzer=\
com.example.analyzer.MyFailureAnalyzer
# 事件监听器
org.springframework.boot.SpringApplicationRunListener=\
com.example.listener.MyListenerSpring Boot 3.x 变化
Spring Boot 3.0+ 使用 SPI 机制替代 spring.factories:
META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports# 每个配置类一行
com.example.autoconfig.MyAutoConfiguration
com.example.autoconfig.OtherAutoConfigurationjava
// 源码变化
// Spring Boot 2.7-
AutoConfigurationImportSelector.getAutoConfigurationEntry()
// Spring Boot 3.0+
AutoConfigurationImportSelector.getAutoConfigurationEntry() {
// 使用 imports 文件替代 factories
}五、自定义 Starter
项目结构
my-spring-boot-starter/
├── pom.xml
└── src/main/java/com/example/starter/
├── MyAutoConfiguration.java
├── MyProperties.java
└── MyService.java
// 使用方项目
├── pom.xml
└── src/main/resources/
└── META-INF/
└── spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports
或 META-INF/spring.factories1. 定义配置属性类
java
// MyProperties.java
@ConfigurationProperties(prefix = "my")
public class MyProperties {
private boolean enabled = true;
private String host = "localhost";
private int port = 8080;
private List<String> whitelist = new ArrayList<>();
// getters/setters
}2. 定义服务类
java
// MyService.java
public class MyService {
private final MyProperties properties;
public MyService(MyProperties properties) {
this.properties = properties;
}
public void doSomething() {
System.out.println("MyService: " + properties);
}
}3. 定义自动配置类
java
// MyAutoConfiguration.java
@AutoConfiguration
@EnableConfigurationProperties(MyProperties.class)
@ConditionalOnProperty(prefix = "my", name = "enabled", havingValue = "true", matchIfMissing = true)
public class MyAutoConfiguration {
@Bean
@ConditionalOnMissingBean(MyService.class)
public MyService myService(MyProperties properties) {
return new MyService(properties);
}
}4. 注册自动配置(Spring Boot 2.7-)
properties
# src/main/resources/META-INF/spring.factories
org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
com.example.starter.MyAutoConfiguration5. 注册自动配置(Spring Boot 3.0+)
properties
# src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports
com.example.starter.MyAutoConfiguration6. 使用方
xml
<dependency>
<groupId>com.example</groupId>
<artifactId>my-spring-boot-starter</artifactId>
<version>1.0.0</version>
</dependency>yaml
my:
enabled: true
host: localhost
port: 9090
whitelist:
- item1
- item2java
@SpringBootApplication
public class App {
public static void main(String[] args) {
var ctx = SpringApplication.run(App.class, args);
var service = ctx.getBean(MyService.class);
service.doSomething();
}
}六、自动配置优先级
优先级从高到低
1. 命令行参数
java -jar app.jar --spring.datasource.url=jdbc:mysql://...
2. ServletConfig / ServletContext 参数
3. JNDI
4. Java System properties
System.setProperty("spring.datasource.url", "...")
5. OS 环境变量
6. 随机值覆盖属性(spring.ramdom.*)
7. JAR 包外配置文件
./config/application.yml
8. JAR 包内配置文件
classpath:application.yml
9. @PropertySource 加载
10. 默认属性(spring-boot-defaults)配置加载顺序
启动类加载 → application.yml → application-{profile}.yml → application.properties
↓
Spring Boot 默认值(最低优先级)七、@EnableConfigurationProperties vs @ConfigurationPropertiesScan
java
// 方式1:@EnableConfigurationProperties(推荐在配置类上使用)
@Configuration
@EnableConfigurationProperties(MyProperties.class)
public class MyAutoConfiguration {
// MyProperties 自动注册为 Bean
}
// 方式2:@ConfigurationPropertiesScan(Spring Boot 2.2+)
@SpringBootApplication
@ConfigurationPropertiesScan // 扫描 @ConfigurationProperties
public class Application { }
// 方式3:@Component + @ConfigurationProperties(不推荐)
@Component
@ConfigurationProperties(prefix = "my")
public class MyProperties { }八、AutoConfigurationImportFilter
过滤不需要的配置
java
// 实现 AutoConfigurationImportFilter
public class MyAutoConfigurationFilter implements AutoConfigurationImportFilter {
@Override
public boolean[] match(String[] autoConfigurationClasses,
AutoConfigurationMetadata autoConfigurationMetadata) {
boolean[] results = new boolean[autoConfigurationClasses.length];
for (int i = 0; i < results.length; i++) {
// 自定义过滤逻辑
results[i] = !autoConfigurationClasses[i].contains("XXX");
}
return results;
}
}注册 Filter
properties
# META-INF/spring.factories
org.springframework.boot.autoconfigure.AutoConfigurationImportFilter=\
com.example.filter.MyAutoConfigurationFilter九、失败分析器 FailureAnalyzer
自定义失败分析器
java
// 端口被占用时的默认提示不够详细
// 自定义分析器
@Component
public class MyBeanMissingFailureAnalyzer implements FailureAnalyzer {
@Override
public AnalysisResult analyze(Throwable failure) {
if (failure instanceof BeanDefinitionStoreException) {
String message = failure.getMessage();
if (message.contains("MyBean")) {
return FailureResult.withCause("MyBean 初始化失败,请检查配置")
.withSolution("确保添加了 @EnableMyFeature 注解");
}
}
return null; // 不处理,返回 null
}
}properties
# META-INF/spring.factories
org.springframework.boot.autoconfigure.FailureAnalyzer=\
com.example.analyzer.MyBeanMissingFailureAnalyzer十、面试高频问题
Q1: 自动配置原理是什么?
@EnableAutoConfiguration启用自动配置AutoConfigurationImportSelector读取spring.factories- 根据
@Conditional条件筛选配置类 - 使用
@Bean注册组件 - 用户配置优先于自动配置
Q2: 如何排除某个自动配置类?
java
@SpringBootApplication(exclude = DataSourceAutoConfiguration.class)
// 或
spring.autoconfigure.exclude=org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfigurationQ3: @ConditionalOnMissingBean 有什么用?
- 防止重复注册 Bean
- 允许用户自定义覆盖默认配置
- 用户定义的 Bean 优先于自动配置
Q4: Spring Boot 3.x 自动配置有什么变化?
spring.factories改为META-INF/spring/*.imports- 每行一个完全限定名
- 更好的 IDE 支持
Q5: 如何自定义 starter?
- 创建工程,引入 spring-boot-starter
- 定义配置属性类
@ConfigurationProperties - 定义服务类
- 定义自动配置类
@AutoConfiguration - 注册到
META-INF/spring/*.imports
Q6: 自动配置何时生效?
- 应用启动时
refreshContext()阶段 - 按配置类中
@Conditional条件判断 - 配置类被解析后
@Bean方法执行
十一、下一章预告
下一章我们将学习 Spring Boot starter 与起步依赖:
- starter 依赖管理机制
- 常用 starter 详解
- 如何排除/替换内置 starter