Spring Boot 自动配置原理,看完终于不慌了

10 阅读2分钟

用了两年 Spring Boot,@SpringBootApplication 一加就什么都能用。但一直不知道背后到底发生了什么。直到最近面试被深挖,才认真看了一遍源码。

从一个注解开始

@SpringBootApplication
public class Application {
    public static void main(String[] args) {
        SpringApplication.run(Application.class, args);
    }
}

@SpringBootApplication 其实是个组合注解:

@SpringBootConfiguration      // 就是 @Configuration,标记配置类
@EnableAutoConfiguration      // 核心:开启自动配置
@ComponentScan                // 扫描当前包及子包的 @Component

重点在 @EnableAutoConfiguration。

@EnableAutoConfiguration

@Import(AutoConfigurationImportSelector.class)
public @interface EnableAutoConfiguration {
}

它通过 @Import 导入了 AutoConfigurationImportSelector,这个类会去读一个文件:

META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports

这个文件里列出了所有自动配置类的全限定名,大概长这样:

org.springframework.boot.autoconfigure.web.servlet.WebMvcAutoConfiguration
org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration
org.springframework.boot.autoconfigure.redis.RedisAutoConfiguration
org.springframework.boot.autoconfigure.security.SecurityAutoConfiguration
...

Spring Boot 启动的时候,把这些配置类全部加载进来。

以 DataSource 为例

@AutoConfiguration
@ConditionalOnClass({ DataSource.class, EmbeddedDatabaseType.class })  // classpath 下有这些类才生效
@EnableConfigurationProperties(DataSourceProperties.class)              // 绑定 application.yml 的配置
public class DataSourceAutoConfiguration {

    @Bean
    @ConditionalOnMissingBean                                           // 用户没自己定义才创建
    public DataSource dataSource(DataSourceProperties properties) {
        return properties.initializeDataSourceBuilder().build();
    }
}

逻辑很清晰:

  1. @ConditionalOnClass:classpath 下有 DataSource 类才激活(你引入了 mysql-connector 就有)
  2. @ConditionalOnMissingBean:如果你自己定义了 DataSource Bean,就不创建了
  3. DataSourceProperties:从 application.yml 里读 spring.datasource.* 配置

所以你只要在 yml 里配了数据库信息,Spring Boot 就自动帮你创建 DataSource。不需要写任何 Java 代码。

条件注解家族

注解含义
@ConditionalOnClassclasspath 有某个类才生效
@ConditionalOnMissingClassclasspath 没有某个类才生效
@ConditionalOnBean容器里有某个 Bean 才生效
@ConditionalOnMissingBean容器里没有某个 Bean 才创建
@ConditionalOnProperty配置属性满足条件才生效
@ConditionalOnWebApplication是 Web 应用才生效

这些条件注解是自动配置的核心——满足条件就生效,不满足就跳过。所以引入一堆 starter 也不会冲突。

自定义自动配置

你也可以写自己的 starter:

// 1. 定义配置属性
@ConfigurationProperties(prefix = "myservice")
public class MyServiceProperties {
    private String apiKey;
    private int timeout = 5000;
    // getter/setter
}

// 2. 写自动配置类
@AutoConfiguration
@ConditionalOnClass(MyClient.class)
@EnableConfigurationProperties(MyServiceProperties.class)
public class MyServiceAutoConfiguration {

    @Bean
    @ConditionalOnMissingBean
    public MyClient myClient(MyServiceProperties properties) {
        return new MyClient(properties.getApiKey(), properties.getTimeout());
    }
}

// 3. 注册到 imports 文件
// META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports
com.example.MyServiceAutoConfiguration

别人引入你的 starter 依赖后,配一下 myservice.api-key 就能直接用了。

怎么排查自动配置

启动时加参数,看哪些自动配置生效了、哪些被跳过了:

java -jar app.jar --debug

或者在 application.yml 里:

debug: true

输出里会有 CONDITIONS EVALUATION REPORT,列出每个配置类的匹配/不匹配条件:

Positive matches:
   DataSourceAutoConfiguration matched:
      - @ConditionalOnClass found required classes

Negative matches:
   RedisAutoConfiguration did not match:
      - @ConditionalOnClass did not find required class 'redis.clients.jedis.Jedis'

总结

Spring Boot 自动配置的原理就是:@EnableAutoConfiguration → 读取 imports 文件 → 加载所有配置类 → 每个配置类用条件注解判断是否生效。满足条件就自动创建 Bean,不满足就跳过。你只需要引入 starter + 配 yml,剩下的框架帮你搞定。