
人这一生,像在排队等一碗汤,排到了,碗却碎了。
可还得蹲下,把碎片舔干净------因为那上面,还沾着点咸味。
文章目录
-
- [一、 自动装配的整体流程概览](#一、 自动装配的整体流程概览)
- 二、各流程详细解析
-
- 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 引入)。
完整流程如下:
- Spring Boot 应用启动 →
SpringApplication.run() - 刷新容器前,处理
@Import注解 @EnableAutoConfiguration导入AutoConfigurationImportSelectorAutoConfigurationImportSelector读取所有候选的自动配置类- 根据
@Conditional条件过滤,决定哪些配置类真正生效 - 生效的配置类中的
@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)
- 加载
ApplicationContextInitializer和ApplicationListener - 重要: 准备环境(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注解
执行链路:
ConfigurationClassPostProcessor扫描所有已注册的 BeanDefinition- 发现启动类上有
@Configuration→ 标记为配置类 - 解析启动类注解时,发现
@Import(AutoConfigurationImportSelector.class) - 立即调用
AutoConfigurationImportSelector.selectImports()方法 selectImports()核心逻辑:- 通过类路径扫描所有 jar 包中的
META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports文件 - 合并所有文件内容,得到 250+ 个候选自动配置类全限定名列表
- 应用 exclude、去重、排序(@AutoConfigureOrder)
- 通过类路径扫描所有 jar 包中的
- 返回 String[] 类名列表
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 条件注解体系,在运行时精准判断哪些组件应当被注册,从而实现"按需装配、零配置启动"的开发体验。