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

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

从一个注解开始

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

@SpringBootApplication 其实是个组合注解:

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

重点在 @EnableAutoConfiguration。

@EnableAutoConfiguration

java 复制代码
@Import(AutoConfigurationImportSelector.class)
public @interface EnableAutoConfiguration {
}

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

bash 复制代码
META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports

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

erlang 复制代码
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 为例

java 复制代码
@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 代码。

条件注解家族

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

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

自定义自动配置

你也可以写自己的 starter:

java 复制代码
// 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 就能直接用了。

怎么排查自动配置

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

bash 复制代码
java -jar app.jar --debug

或者在 application.yml 里:

yaml 复制代码
debug: true

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

sql 复制代码
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,剩下的框架帮你搞定。

相关推荐
岁月宁静8 小时前
AI 应用开发工程师简历怎么写:HR 初筛、技术复筛、面试追问,三道关卡各看什么?
人工智能·python·面试
Dream it possible!10 小时前
LeetCode 面试经典 150_多维动态规划_交错字符串(97_C++_中等)
算法·leetcode·面试·动态规划
高晶11 小时前
Android 任务管理器开发实战指南
程序员
yeccheng14 小时前
MySQL 索引超详解:从底层 B+ 树到面试高频考点
java·开发语言·jvm·mysql·面试
楠风测开18 小时前
Web 兼容性 + AI 跨浏览器
程序员
j7~20 小时前
【C++ 八股文】(篇四)C++11 新特性
开发语言·c++·面试·c++11·八股文
陈随易1 天前
Rolldown 把插件改动回传提速 26 倍
前端·后端·程序员
陈随易1 天前
Vue 编译器换掉 source map,快了三四成
前端·后端·程序员
皮皮林5511 天前
40亿个QQ号,限制1G内存,如何去重?
程序员
nice_lcj5201 天前
Java Lambda 表达式入门:怎么写、怎么用、常用方法有哪些
java·开发语言·后端·面试