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,剩下的框架帮你搞定。

相关推荐
救救孩子把3 小时前
AI面试八股文-21_21-多模态Agent面试题-Vision-Language-Agent
人工智能·面试·职场和发展·llava·多模态agent
ShineWinsu5 小时前
对于JavaScript:JavaScript基础语法的解析
开发语言·前端·javascript·面试·web·基础语法·循环
救救孩子把6 小时前
AI面试八股文-13_12-AI 框架与运维面试题
运维·人工智能·面试
救救孩子把6 小时前
AI面试八股文-14_14-MCP-Skill-Function Calling
人工智能·安全·面试·职场和发展·推理·mcp·functioncall
高晶8 小时前
ARM 嵌入式 Linux 文件系统从入门到实战:目录结构、权限管理、选型与挂载排查全攻略
linux·程序员
米米商聊8 小时前
语音进度显示 100%,为什么还不能判定播放结束?
程序员
帷幕落秋8 小时前
进程服务与文件描述符
linux·运维·面试
高晶8 小时前
C 语言实现 BMS 系统中 SPI 通信协议实战指南
设计模式·程序员
帷幕落秋8 小时前
信号、Ctrl 组合键与进程状态
linux·运维·面试
用户355090174868 小时前
工业 RAG 实战:忠实度从 0.85 调到 0.95,我们做对了这几件事
程序员