1-2 自动配置原理
概念解析
自动配置核心流程
启动类 @SpringBootApplication
↓
@EnableAutoConfiguration
↓
Spring Factories 加载配置类
↓
@Conditional 条件判断
↓
按需配置(需要的才生效)
关键注解
| 注解 | 作用 |
|---|---|
@SpringBootApplication | 组合注解,包含自动配置 |
@EnableAutoConfiguration | 启用自动配置 |
@Import | 导入配置类 |
@Configuration | 标记配置类 |
@Conditional | 条件判断 |
代码示例
1. 查看自动配置报告
application.yml
# 开启自动配置报告(控制台输出)
debug: true
# 或者查看 web 端点
management:
endpoints:
web:
exposure:
include: "*"
访问 http://localhost:8080/actuator/conditions 查看详细报告
2. 自定义自动配置类
步骤 1:创建配置类
package com.example.demo.config;
@Configuration
@ConditionalOnClass(UserService.class) // 当 UserService 在 classpath 时生效
@ConditionalOnProperty(
prefix = "app.user",
name = "enabled",
havingValue = "true",
matchIfMissing = true // 缺失时也生效
)
public class UserAutoConfiguration {
@Bean
@ConditionalOnMissingBean // 容器中不存在时才创建
public UserService userService() {
return new UserServiceImpl();
}
}
步骤 2:注册配置类
# resources/META-INF/spring.factories
org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
com.example.demo.config.UserAutoConfiguration
或者(Spring Boot 2.7+):
# resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports
com.example.demo.config.UserAutoConfiguration
3. 排除自动配置
@SpringBootApplication(exclude = {
DataSourceAutoConfiguration.class,
HibernateJpaAutoConfiguration.class
})
public class SpringBootApplication { }
源码解读
@SpringBootApplication 源码
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
@SpringBootConfiguration
@EnableAutoConfiguration
@ComponentScan(excludeFilters = {
@Filter(type = FilterType.CUSTOM, classes = TypeExcludeFilter.class),
@Filter(type = FilterType.CUSTOM,
classes = AutoConfigurationImportFilter.class)
})
public @interface SpringBootApplication {
// ...
}
@EnableAutoConfiguration 源码
@AutoConfigurationPackage // 记录主类的包名
@Import(AutoConfigurationImportSelector.class) // 关键!
public @interface EnableAutoConfiguration {
String ENABLED_OVERRIDE_PROPERTY = "spring.boot.enableautoconfiguration";
Class<?>[] exclude() default {};
String[] excludeName() default {};
}
AutoConfigurationImportSelector 执行流程
public class AutoConfigurationImportSelector
implements DeferredImportSelector {
// 核心方法:返回需要导入的自动配置类
@Override
public String[] selectImports(AnnotationMetadata annotationMetadata) {
// 1. 获取 EnableAutoConfiguration 注解的属性
// 2. 从 spring.factories 读取所有候选配置
// 3. 根据 @Conditional 条件过滤
// 4. 去除重复配置
// 5. 返回最终生效的配置类名数组
}
}
常见坑点
⚠️ 坑 1:自动配置不生效
排查步骤:
- 检查是否被
@Conditional排除 - 检查依赖是否引入
- 查看自动配置报告
- 检查是否被 exclude 排除
⚠️ 坑 2:多个配置类冲突
问题:多个候选人配置了同一个 Bean
解决:使用 @ConditionalOnMissingBean 确保只配置一个
@Bean
@ConditionalOnMissingBean(UserService.class)
public UserService userService() {
return new UserServiceImpl();
}
⚠️ 坑 3:自动配置顺序问题
问题:配置类之间的依赖顺序不对
解决:使用 @AutoConfigureBefore / @AutoConfigureAfter
@Configuration
@AutoConfigureAfter(DataSourceAutoConfiguration.class)
public class MyBatisAutoConfiguration { }
面试题
Q1:自动配置是怎么实现的?
参考答案:
-
@EnableAutoConfiguration 通过
@Import导入AutoConfigurationImportSelector -
selectImports() 方法执行时:
- 从
META-INF/spring.factories读取所有EnableAutoConfiguration配置 - 读取
META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports(2.7+) - 根据
@Conditional条件进行过滤 - 去除重复和已排除的配置
- 从
-
按需配置:Spring Boot 遵循"按需配置"原则,只加载符合条件的配置
Q2:spring.factories 是什么?
参考答案:
spring.factories 是 Spring 框架的 SPI(Service Provider Interface)机制配置文件,格式为:
# key = 接口/抽象类
# value = 实现类(多个用逗号分隔)
org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
com.example.demo.config.UserAutoConfiguration,\
com.example.demo.config.OrderAutoConfiguration
注意:Spring Boot 2.7+ 推荐使用 AutoConfiguration.imports 文件替代
Q3:如何自定义 starter?
参考答案:
1. 创建 autoconfigure 模块
my-starter/
└── my-starter-autoconfigure/
├── pom.xml
└── src/main/java/
└── com/example/config/
└── MyAutoConfiguration.java
2. 创建 starter 模块
my-starter/
├── my-starter-autoconfigure/
└── my-starter/
└── src/main/resources/
└── META-INF/
└── spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports
3. starter 的 pom.xml 只包含依赖引用
<dependencies>
<dependency>
<groupId>com.example</groupId>
<artifactId>my-starter-autoconfigure</artifactId>
<version>1.0.0</version>
</dependency>
</dependencies>
使用方只需引入 starter 即可:
<dependency>
<groupId>com.example</groupId>
<artifactId>my-starter</artifactId>
</dependency>