Spring Boot 自动装配(Auto-Configuration)深度实现原理全解析

人这一生,像在排队等一碗汤,排到了,碗却碎了。

可还得蹲下,把碎片舔干净------因为那上面,还沾着点咸味。

文章目录

    • [一、 自动装配的整体流程概览](#一、 自动装配的整体流程概览)
    • 二、各流程详细解析
      • 1.启动类解析
        • [(1) @SpringBootConfiguration](#(1) @SpringBootConfiguration)
        • [(2) @EnableAutoConfiguration ------ 自动配置的魔法所在](#(2) @EnableAutoConfiguration —— 自动配置的魔法所在)
        • [(3) @ComponentScan ------ 组件扫描](#(3) @ComponentScan —— 组件扫描)
      • [2. **应用启动:SpringApplication.run()**](#2. 应用启动:SpringApplication.run())
      • [3. 准备并刷新 ApplicationContext](#3. 准备并刷新 ApplicationContext)
      • [4. refresh() 方法的 12 个标准步骤(Spring 容器生命周期)](#4. refresh() 方法的 12 个标准步骤(Spring 容器生命周期))
      • [5. 第 5 步:invokeBeanFactoryPostProcessors() ------ 导入候选配置类](#5. 第 5 步:invokeBeanFactoryPostProcessors() —— 导入候选配置类)
      • [6. 条件过滤发生时机](#6. 条件过滤发生时机)
      • [7. 第 11 步:finishBeanFactoryInitialization() ------ 执行 @Bean 方法](#7. 第 11 步:finishBeanFactoryInitialization() —— 执行 @Bean 方法)
      • [8. 启动完成](#8. 启动完成)
    • 三、结语:

Spring Boot 的自动装配是它最强大的特性之一,让开发者几乎不用写配置就能跑起一个完整的应用。那么,这个"魔法"到底是怎么实现的?本文从宏观流程到底层源码,一步步拆解自动装配的完整实现机制(基于 Spring Boot 3.x 版本)。

一、 自动装配的整体流程概览

自动装配的核心入口是 @EnableAutoConfiguration(通常通过 @SpringBootApplication 引入)。

完整流程如下:

  1. Spring Boot 应用启动 → SpringApplication.run()
  2. 刷新容器前,处理 @Import 注解
  3. @EnableAutoConfiguration 导入 AutoConfigurationImportSelector
  4. AutoConfigurationImportSelector 读取所有候选的自动配置类
  5. 根据 @Conditional 条件过滤,决定哪些配置类真正生效
  6. 生效的配置类中的 @Bean 方法被执行,注册各种 Bean 到容器

二、各流程详细解析

1.启动类解析

在每一个 Spring Boot 项目中,你都会看到一个标志性的启动类,通常长这样:

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

这个看起来简单的 @SpringBootApplication 注解,其实是 Spring Boot 能够"开箱即用"的核心秘密之一。它并不是一个单一的注解,而是由多个注解组合而成,承担了组件扫描、自动配置、Spring Boot 应用标识等多个重要职责。

@SpringBootApplication 是 Spring Boot 最核心的注解,从 Spring Boot 1.2.0 开始引入,它实际上等价于以下三个注解的组合:

sql 复制代码
	@Target(ElementType.TYPE)
	@Retention(RetentionPolicy.RUNTIME)
	@Documented
	@Inherited
	@SpringBootConfiguration
	@EnableAutoConfiguration
	@ComponentScan
	public @interface SpringBootApplication { ... }

我们逐个来看。

(1) @SpringBootConfiguration

这个注解本质上是 @Configuration 的变种,继承自它。

  • @Configuration:标记这是一个配置类,可以定义 Bean(通过 @Bean 方法)。
  • @SpringBootConfiguration:在保留 @Configuration 功能的基础上,明确表示"这是 Spring Boot 项目的配置类",方便框架内部识别。

实际使用中,你几乎不会单独写 @SpringBootConfiguration,因为 @SpringBootApplication 已经包含了它。

(2) @EnableAutoConfiguration ------ 自动配置的魔法所在

这是 Spring Boot "约定大于配置" 最关键的部分。

作用:告诉 Spring Boot 根据类路径下的 jar 包依赖,自动推测并配置你可能需要的 Bean。

例如:

  • 引入了 spring-boot-starter-web → 自动配置 DispatcherServlet、Tomcat 等。
  • 引入了 spring-boot-starter-data-jdbc → 自动配置 DataSource、JdbcTemplate 等。
  • 引入了 spring-boot-starter-redis → 自动配置 RedisTemplate 等。

结构:

sql 复制代码
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
@AutoConfigurationPackage
@Import(AutoConfigurationImportSelector.class)
public @interface EnableAutoConfiguration {

    String ENABLED_OVERRIDE_PROPERTY = "spring.boot.enableautoconfiguration";

    Class<?>[] exclude() default {};

    String[] excludeName() default {};
}

实现原理:

  • 通过 @Import(AutoConfigurationImportSelector.class) 导入大量 xxxAutoConfiguration 类。
  • 这些自动配置类都带有 @ConditionalOnClass@ConditionalOnMissingBean@ConditionalOnProperty 等条件注解,只有满足条件时才会生效。
  • 配置优先级:默认值 < application.properties/yml < 自定义 Bean。
(3) @ComponentScan ------ 组件扫描

作用:自动扫描当前启动类所在包及其子包下的组件(@Component、@Service、@Repository、@Controller 等),并注册为 Bean。

默认扫描规则:

  • 扫描启动类所在包及所有子包。
  • 可自定义:@ComponentScan(basePackages = "com.example.other")excludeFilters 排除某些类。

2. 应用启动:SpringApplication.run()

java 复制代码
public static ConfigurableApplicationContext run(Class<?>[] primarySources, String[] args) {
    return new SpringApplication(primarySources).run(args);
}
  • 创建 SpringApplication 实例
  • 设置应用类型(Servlet/Reactive)
  • 加载 ApplicationContextInitializerApplicationListener
  • 重要: 准备环境(Environment),包括加载 application.properties/yml

3. 准备并刷新 ApplicationContext

SpringApplication.run() 内部调用:

java 复制代码
ConfigurableApplicationContext context = createApplicationContext();
prepareContext(context, ...);
refreshContext(context);  // ← 这里是 Spring 容器的标准刷新流程

自动装配主要发生在 refreshContext() 中,它委托给 AbstractApplicationContext.refresh()关键方法

4. refresh() 方法的 12 个标准步骤(Spring 容器生命周期)

Spring 容器刷新有固定 12 步,自动装配主要集中在第 3~6 步

步骤序号 方法名 说明 自动装配相关性
1 prepareRefresh() 准备刷新,设置启动时间、标记活跃状态
2 obtainFreshBeanFactory() 创建并加载 BeanFactory
3 prepareBeanFactory() 为 BeanFactory 添加后处理器(如 ApplicationContextAwareProcessor)
4 postProcessBeanFactory() 子类扩展点(Web 环境添加 Servlet 相关)
5 invokeBeanFactoryPostProcessors() 核心!执行所有 BeanFactoryPostProcessor 自动装配入口
6 registerBeanPostProcessors() 注册 BeanPostProcessor 中(影响后续 Bean 创建)
7 initMessageSource() 初始化消息源
8 initApplicationEventMulticaster() 初始化事件广播器
9 onRefresh() 子类扩展(WebServer 初始化)
10 registerListeners() 注册监听器
11 finishBeanFactoryInitialization() 实例化所有剩余的单例 Bean 执行 @Bean 方法
12 finishRefresh() 发布 ContextRefreshedEvent

自动装配的"两大关键时刻"就在 第 5 步第 11 步

5. 第 5 步:invokeBeanFactoryPostProcessors() ------ 导入候选配置类

这是自动装配的真正起点

  • 执行所有实现了 BeanFactoryPostProcessor 的处理器
  • 其中最关键的是 Spring 内置的 ConfigurationClassPostProcessor
  • 这个处理器负责解析所有 @Configuration 类和 @Import 注解

执行链路:

  1. ConfigurationClassPostProcessor 扫描所有已注册的 BeanDefinition
  2. 发现启动类上有 @Configuration→ 标记为配置类
  3. 解析启动类注解时,发现 @Import(AutoConfigurationImportSelector.class)
  4. 立即调用 AutoConfigurationImportSelector.selectImports() 方法
  5. selectImports() 核心逻辑:
    • 通过类路径扫描所有 jar 包中的 META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports 文件
    • 合并所有文件内容,得到 250+ 个候选自动配置类全限定名列表
    • 应用 exclude、去重、排序(@AutoConfigureOrder)
  6. 返回 String\[\] 类名列表
  7. ConfigurationClassPostProcessor 把这些类当作"被 @Import 导入的配置类"加入解析队列

这一步的产出:所有候选自动配置类被注册为 ConfigurationClass 候选(但还未实例化)。

6. 条件过滤发生时机

  • 并非 selectImports() 时过滤,而是在 ConfigurationClassPostProcessor.processConfigBeanDefinitions()
  • 逐个解析每个候选配置类,检查其上的 @ConditionalXXX 注解
  • 使用 ConditionEvaluator 调用每个 Condition.matches() 方法
  • 只有所有条件都满足的配置类才真正被保留并注册为 BeanDefinition

7. 第 11 步:finishBeanFactoryInitialization() ------ 执行 @Bean 方法

  • 实例化所有非懒加载的单例 Bean
  • 当轮到自动配置类(如 DataSourceAutoConfiguration)实例化时:
    • 因为它是 @Configuration 类,会被 CGLIB 代理增强
    • 代理拦截所有 @Bean 方法调用
    • 再次检查该 @Bean 方法上的 @ConditionalOnMissingBean 等条件
    • 条件满足 → 执行方法 → 创建并注册 Bean(如 HikariDataSource、RedisTemplate 等)
    • 条件不满足 → 跳过,不创建该 Bean

8. 启动完成

  • 容器刷新完毕,所有自动配置的 Bean 已就位
  • 应用正式启动,Tomcat/Jetty/Netty 等 Web 服务器开始监听端口

三、结语:

SpringBoot 以 @EnableAutoConfiguration 为入口,通过 AutoConfigurationImportSelector 动态加载候选配置类,再借助 Spring 强大的 @Conditional 条件注解体系,在运行时精准判断哪些组件应当被注册,从而实现"按需装配、零配置启动"的开发体验。

相关推荐
Lsk_Smion13 小时前
力扣实训 _ [33].搜索旋转排序数组 _ [92].翻转链表Ⅱ
java·数据结构·算法
j_xxx404_13 小时前
Linux 线程同步硬核解析:从条件变量、阻塞队列到信号量环形队列
linux·运维·服务器·c++·人工智能·ai·中间件
AI人工智能+电脑小能手14 小时前
【大白话说Java面试题 第86题】【Mysql篇】第16题:MySQL 中锁的种类与行锁实现原理?
java·开发语言·数据库·mysql·面试
不爱编程的小陈14 小时前
Go内存模型与GC机制:高性能编程的核心
开发语言·后端·golang
code2roc14 小时前
SpringBoot整合Milvus向量数据库
数据库·spring boot·milvus·向量化
苏渡苇14 小时前
Seata 番外篇:使用 docker-compose 部署 Seata Server(TC)及 K8S 部署 Seata 高可用
spring boot·docker·微服务·容器·kubernetes·seata·springcloud
日月云棠14 小时前
12 Enum —— 枚举类型的底层实现
java·后端
工位植物人14 小时前
深入理解Java中的类、抽象类、接口与枚举类
后端
用户21816970493014 小时前
Gin (二) 参数 路由分组
后端
用户9258079114814 小时前
nacos服务注册源码浅析
后端