Skip to content

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.MyAutoConfiguration

SpringApplication 启动流程

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_db

Actuator 监控

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: true
bash
# 常用端点
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})

系统学习 Java 生态,深入底层架构