Spring Boot 自动配置原理
Spring Boot 的核心魔法是"约定优于配置"。理解自动配置原理,能让你更好地定制和扩展 Spring Boot 应用。
自动配置的入口
java
@SpringBootApplication
public class MyApplication {
public static void main(String[] args) {
SpringApplication.run(MyApplication.class, args);
}
}
// @SpringBootApplication 是三个注解的组合:
// @SpringBootConfiguration — 等同于 @Configuration
// @EnableAutoConfiguration — 开启自动配置(核心!)
// @ComponentScan — 扫描当前包及子包自动配置原理
@EnableAutoConfiguration
↓
@Import(AutoConfigurationImportSelector.class)
↓
AutoConfigurationImportSelector.selectImports()
↓
读取 META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports
(Spring Boot 2.7+ 新格式,旧版是 spring.factories)
↓
加载所有自动配置类(如 DataSourceAutoConfiguration)
↓
@Conditional 条件过滤(只有满足条件的才生效)
↓
注册 Bean 到容器java
// 查看生效的自动配置
// 启动时加 --debug 参数,或:
@SpringBootApplication
public class MyApplication {
public static void main(String[] args) {
SpringApplication app = new SpringApplication(MyApplication.class);
app.setAdditionalProfiles("debug");
app.run(args);
}
}
// 或在 application.properties 中:
// debug=true自动配置类示例
java
// Spring Boot 内置的 DataSourceAutoConfiguration(简化版)
@AutoConfiguration
@ConditionalOnClass({ DataSource.class, EmbeddedDatabaseType.class })
@ConditionalOnMissingBean(type = "io.r2dbc.spi.ConnectionFactory")
@EnableConfigurationProperties(DataSourceProperties.class)
@Import({ DataSourcePoolMetadataProvidersConfiguration.class,
DataSourceInitializationConfiguration.class })
public class DataSourceAutoConfiguration {
@Configuration(proxyBeanMethods = false)
@Conditional(EmbeddedDatabaseCondition.class)
@ConditionalOnMissingBean({ DataSource.class, XADataSource.class })
@Import(EmbeddedDataSourceConfiguration.class)
protected static class EmbeddedDatabaseConfiguration { }
@Configuration(proxyBeanMethods = false)
@ConditionalOnMissingBean({ DataSource.class, XADataSource.class })
@ConditionalOnProperty(prefix = "spring.datasource", name = "type")
static class PooledDataSourceConfiguration {
// 根据 spring.datasource.type 创建连接池
}
}自定义 Starter
my-spring-boot-starter/
├── my-autoconfigure/
│ ├── src/main/java/
│ │ └── com/example/
│ │ ├── MyProperties.java
│ │ ├── MyService.java
│ │ └── MyAutoConfiguration.java
│ └── src/main/resources/
│ └── META-INF/spring/
│ └── org.springframework.boot.autoconfigure.AutoConfiguration.imports
└── my-starter/
└── pom.xml (只依赖 my-autoconfigure,不写代码)java
// 1. 配置属性类
@ConfigurationProperties(prefix = "my.service")
public class MyProperties {
private String apiUrl = "https://api.example.com";
private int timeout = 5000;
private boolean enabled = true;
// getter/setter
}
// 2. 服务类
public class MyService {
private final MyProperties properties;
public MyService(MyProperties properties) {
this.properties = properties;
}
public String call(String endpoint) {
// 使用 properties.getApiUrl() 等
return "result";
}
}
// 3. 自动配置类
@AutoConfiguration
@ConditionalOnClass(MyService.class)
@ConditionalOnProperty(prefix = "my.service", name = "enabled",
havingValue = "true", matchIfMissing = true)
@EnableConfigurationProperties(MyProperties.class)
public class MyAutoConfiguration {
@Bean
@ConditionalOnMissingBean // 用户自定义时不覆盖
public MyService myService(MyProperties properties) {
return new MyService(properties);
}
}# META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports
com.example.MyAutoConfigurationSpringApplication 启动流程
SpringApplication.run()
↓
1. 创建 SpringApplication 实例
- 推断应用类型(SERVLET/REACTIVE/NONE)
- 加载 ApplicationContextInitializer
- 加载 ApplicationListener
- 推断主类
2. 发布 ApplicationStartingEvent
3. 准备环境(Environment)
- 加载 application.properties/yml
- 处理命令行参数
- 发布 ApplicationEnvironmentPreparedEvent
4. 创建 ApplicationContext
- SERVLET → AnnotationConfigServletWebServerApplicationContext
- REACTIVE → AnnotationConfigReactiveWebServerApplicationContext
5. 准备 ApplicationContext
- 执行 ApplicationContextInitializer
- 加载 Bean 定义(@SpringBootApplication 扫描)
6. 刷新 ApplicationContext(核心!)
- 执行所有 BeanFactoryPostProcessor
- 实例化所有单例 Bean
- 启动内嵌 Web 服务器(Tomcat/Netty)
7. 发布 ApplicationStartedEvent
8. 执行 ApplicationRunner / CommandLineRunner
9. 发布 ApplicationReadyEvent配置文件优先级
优先级从高到低:
1. 命令行参数:--server.port=9090
2. JNDI 属性
3. Java 系统属性:-Dserver.port=9090
4. 操作系统环境变量:SERVER_PORT=9090
5. application-{profile}.properties(外部)
6. application.properties(外部)
7. application-{profile}.properties(jar 包内)
8. application.properties(jar 包内)
9. @PropertySource 注解
10. 默认属性yaml
# application.yml — 多环境配置
spring:
profiles:
active: dev # 激活 dev profile
---
spring:
config:
activate:
on-profile: dev
datasource:
url: jdbc:mysql://localhost:3306/dev_db
---
spring:
config:
activate:
on-profile: prod
datasource:
url: jdbc:mysql://prod-server:3306/prod_dbActuator 监控
xml
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>yaml
management:
endpoints:
web:
exposure:
include: health,info,metrics,env,beans,mappings
endpoint:
health:
show-details: always
info:
env:
enabled: truebash
# 常用端点
GET /actuator/health # 健康检查
GET /actuator/info # 应用信息
GET /actuator/metrics # 指标数据
GET /actuator/env # 环境变量
GET /actuator/beans # 所有 Bean
GET /actuator/mappings # 所有 URL 映射
GET /actuator/loggers # 日志级别
POST /actuator/loggers/com.example # 动态修改日志级别自动配置调试技巧
bash
# 查看哪些自动配置生效/未生效
java -jar app.jar --debug 2>&1 | grep "Positive\|Negative matches"
# 排除特定自动配置
@SpringBootApplication(exclude = {DataSourceAutoConfiguration.class})