【Spring Boot】自动配置原理:@EnableAutoConfiguration 与 Starter 机制
🔑 关键词:Java、Spring Boot、自动配置、@EnableAutoConfiguration、@Conditional、Starter、SPI
一、什么是自动配置?
Spring Boot 自动配置是指:根据你引入的依赖,自动帮你配置好对应的 Bean,不需要手动写 XML 或 @Bean。
📌 一句话理解 :你在 pom.xml 引入了
spring-boot-starter-web,Spring Boot 就自动帮你配好 DispatcherServlet、视图解析器、JSON 转换器等,开箱即用。
二、自动配置的核心流程
@SpringBootApplication
↓
@EnableAutoConfiguration
↓
@Import(AutoConfigurationImportSelector.class)
↓
读取 META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports
↓
加载所有自动配置类(xxxAutoConfiguration)
↓
根据 @Conditional 条件判断是否生效
↓
注册对应的 Bean 到 Spring 容器
三、关键注解详解
3.1 @EnableAutoConfiguration
java
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Import(AutoConfigurationImportSelector.class)
public @interface EnableAutoConfiguration { }
核心是通过 @Import 导入 AutoConfigurationImportSelector,它负责加载所有自动配置类。
3.2 AutoConfigurationImportSelector
java
// 简化版逻辑
public class AutoConfigurationImportSelector implements ImportSelector {
@Override
public String[] selectImports(AnnotationMetadata metadata) {
// 读取 META-INF/spring/...AutoConfiguration.imports 文件
// 返回所有自动配置类的全限定类名
return getCandidateConfigurations(annotationMetadata);
}
}
配置文件位置:
- Spring Boot 3.x:
META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports - Spring Boot 2.x:
META-INF/spring.factories
3.3 @Conditional 系列注解
@Conditional 是自动配置生效的关键------只有满足条件时,配置类才会生效。
| 注解 | 条件 |
|---|---|
@ConditionalOnClass |
classpath 中存在某个类时生效 |
@ConditionalOnMissingClass |
classpath 中不存在某个类时生效 |
@ConditionalOnBean |
容器中存在某个 Bean 时生效 |
@ConditionalOnMissingBean |
容器中不存在某个 Bean 时生效 |
@ConditionalOnProperty |
配置属性满足某个值时生效 |
@ConditionalOnWebApplication |
当前是 Web 应用时生效 |
四、源码解读:Web 自动配置
4.1 ServletWebServerFactoryAutoConfiguration
java
@AutoConfiguration
@ConditionalOnWebApplication(type = Type.SERVLET)
@ConditionalOnClass(DispatcherServlet.class)
public class ServletWebServerFactoryAutoConfiguration {
@Bean
@ConditionalOnMissingBean
public ServletWebServerFactory webServerFactory(
@Value("${server.port:8080}") int port) {
// 创建内嵌 Tomcat
TomcatServletWebServerFactory factory = new TomcatServletWebServerFactory();
factory.setPort(port);
return factory;
}
@Bean
@ConditionalOnMissingBean
public DispatcherServlet dispatcherServlet() {
return new DispatcherServlet();
}
}
解读:
@ConditionalOnWebApplication(type = SERVLET):只有 Servlet 类型 Web 应用才生效@ConditionalOnClass(DispatcherServlet.class):classpath 有 DispatcherServlet 才生效@ConditionalOnMissingBean:如果用户没有自定义,才使用默认配置
这就是"约定优于配置"的实现:
- 有 web 依赖 → 自动配 Tomcat + DispatcherServlet
- 你自定义了 → 用你的,不用默认的
4.2 DataSourceAutoConfiguration(数据源自动配置)
java
@AutoConfiguration
@ConditionalOnClass(DataSource.class)
@EnableConfigurationProperties(DataSourceProperties.class)
public class DataSourceAutoConfiguration {
@Bean
@ConditionalOnMissingBean
@ConditionalOnProperty("spring.datasource.url")
public DataSource dataSource(DataSourceProperties properties) {
return properties.initializeDataSourceBuilder().build();
}
}
解读:
@ConditionalOnClass(DataSource.class):引入了数据库驱动才生效@ConditionalOnProperty("spring.datasource.url"):配置了 URL 才生效@ConditionalOnMissingBean:用户没自定义 DataSource 才创建默认的
五、Starter 机制
5.1 什么是 Starter?
Starter 是一组依赖集合,引入一个 Starter 就等于引入了一组相关依赖,且版本经过验证不会冲突。
xml
<!-- 引入这个 Starter,自动包含: -->
<!-- spring-web, spring-webmvc, jackson, tomcat, ... -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
5.2 常用 Starter
| Starter | 功能 |
|---|---|
spring-boot-starter-web |
Web 开发(MVC + Tomcat + Jackson) |
spring-boot-starter-data-jpa |
JPA 数据访问 |
spring-boot-starter-data-redis |
Redis 操作 |
spring-boot-starter-security |
安全认证 |
spring-boot-starter-test |
测试(JUnit + Mockito) |
spring-boot-starter-actuator |
监控和管理 |
mybatis-spring-boot-starter |
MyBatis 整合 |
5.3 Starter 的组成
一个 Starter 通常包含:
pom.xml:聚合依赖- 自动配置类(
xxxAutoConfiguration) - 配置属性类(
xxxProperties) AutoConfiguration.imports或spring.factories:注册自动配置类
六、自定义 Starter
三步走:
① 配置属性类:
java
@ConfigurationProperties(prefix = "my.log")
public class LogProperties {
private boolean enabled = true;
private String prefix = "[LOG]";
// getter/setter
}
② 自动配置类:
java
@AutoConfiguration
@ConditionalOnWebApplication
@EnableConfigurationProperties(LogProperties.class)
public class LogAutoConfiguration {
@Bean
@ConditionalOnMissingBean
public LogInterceptor logInterceptor(LogProperties props) {
return new LogInterceptor(props);
}
@Bean
public WebMvcConfigurer logWebMvcConfigurer(LogInterceptor interceptor) {
return new WebMvcConfigurer() {
@Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(interceptor).addPathPatterns("/**");
}
};
}
}
③ 注册 :在 META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports 中写入 com.example.LogAutoConfiguration。
其他项目引入该 Starter 依赖后,配置 my.log.enabled=true 即可自动生效。
七、如何查看哪些自动配置生效了?
7.1 启动日志
启动时设置 debug=true:
yaml
debug: true
或命令行:java -jar app.jar --debug
控制台会输出 CONDITIONS EVALUATION REPORT:
- Positive matches:生效的自动配置
- Negative matches:未生效的自动配置及原因
7.2 IDEA 查看
安装 Spring Boot Assistant 插件,可以在 yml 中直接看到配置对应的自动配置类。
八、面试高频问题
Q1:Spring Boot 自动配置的原理?
答 :
@SpringBootApplication包含@EnableAutoConfiguration,它通过@Import(AutoConfigurationImportSelector.class)加载AutoConfiguration.imports中的所有自动配置类。每个配置类上都有@Conditional系列注解,只有满足条件(如 classpath 存在某个类、容器中存在某个 Bean、配置属性满足某个值)时,配置类才会生效并注册对应的 Bean。
Q2:@ConditionalOnBean 和 @ConditionalOnMissingBean 的区别?
答 :
@ConditionalOnBean表示容器中存在 某个 Bean 时才生效;@ConditionalOnMissingBean表示容器中不存在某个 Bean 时才生效。后者常用于提供默认配置------如果用户没有自定义,就使用框架提供的默认 Bean。
Q3:如何自定义 Starter?
答 :三步:① 创建
xxxProperties配置属性类,用@ConfigurationProperties绑定配置项;② 创建xxxAutoConfiguration自动配置类,用@Conditional控制生效条件;③ 在META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports文件中注册配置类的全限定名。
九、总结
| 知识点 | 核心要点 |
|---|---|
| 自动配置原理 | @EnableAutoConfiguration → 加载 imports → @Conditional 条件判断 |
| @Conditional | 控制配置类是否生效的核心注解 |
| Starter | 一组依赖集合 + 自动配置,开箱即用 |
| 自定义 Starter | Properties + AutoConfiguration + imports 文件 |
📝 下一篇预告:《Spring Boot Web 开发》,详解 RESTful API、全局异常处理、拦截器在 Spring Boot 中的实现。