SpringBoot启动流程深度解析:从源码到实战
SpringBoot 启动流程全解析:从源码到面试,一文打通 Bean 生命周期与自动配置
本文将按照真实源码的执行顺序,把 SpringBoot 启动流程、Bean 生命周期、三级缓存、自动配置、SPI 机制、BeanPostProcessor 等核心知识点全部串联起来。无论是应对面试,还是日常排查启动报错,这篇文章都能为你提供清晰的思路。
整体总览:SpringBoot 启动的两大阶段
SpringBoot 的启动过程本质上可以分为两大阶段:
- SpringApplication 实例化阶段:构造器初始化,准备启动所需的基础组件。
- run() 方法执行阶段:真正启动容器、加载 Bean、启动 Web 服务。
入口代码永远是这一行:
@SpringBootApplication
public class Application {
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
}
全局启动流程图
第一阶段:SpringApplication 实例化
当你调用 run 方法时,底层会先 new 一个 SpringApplication 对象。构造器主要做 4 件事:
1. 判断应用类型(WebApplicationType)
Spring 会根据类路径下是否存在特定的类来判断应用类型:
- SERVLET:存在
Servlet、DispatcherServlet等类,判定为普通 Web 应用(Spring MVC)。 - REACTIVE:存在 WebFlux 相关类(如
DispatcherHandler),且不存在 Servlet 类,判定为响应式应用。 - NONE:无 Web 环境相关类,判定为纯后台应用(如定时任务、消息消费者)。
2. 加载并设置 ApplicationContextInitializer(容器初始化器)
通过 Spring 的 SPI 机制,扫描所有 jar 包下的配置文件,找到 key 为 ApplicationContextInitializer 的实现类并保存。
原理解析:在 Spring Boot 2.7 之前,扫描的是
META-INF/spring.factories;在 Spring Boot 2.7 及 3.x 版本中,自动配置相关的 SPI 文件改为了META-INF/spring/org.springframework.boot.context.ApplicationContextInitializer.imports。这些初始化器会在容器刷新(refresh)之前被调用,用于对容器进行自定义扩展。
3. 加载并设置 ApplicationListener(事件监听器)
同样通过 SPI 机制加载所有事件监听器。Spring 内部定义了一系列事件(如 ApplicationStartingEvent、ApplicationReadyEvent),这些监听器用于在启动的各个节点执行自定义逻辑。
4. 推断主类(MainApplicationClass)
通过获取当前线程的堆栈追踪(Stack Trace),找到执行 main 方法的类,也就是你的启动类。这为后续扫描 @SpringBootApplication 提供了基准包路径。
第二阶段:执行 run() 方法(核心启动流程)
这是真正的启动过程,按源码执行顺序拆解为 12 个关键步骤。
步骤 1:启动计时器与获取启动监听器
StopWatch stopWatch = new StopWatch();
stopWatch.start();
- 记录启动耗时。
- 通过 SPI 获取
SpringApplicationRunListener实现(默认是EventPublishingRunListener)。 - 发布
ApplicationStartingEvent(应用开始启动事件)。
步骤 2:准备应用环境 Environment
这一步加载所有配置,是整个应用的配置来源。加载顺序决定了配置的优先级(优先级从高到低):
- 命令行参数(
--server.port=8080) - Java 系统属性(
System.getProperties()) - 操作系统环境变量(
System.getenv()) - 配置文件(
application.properties/application.yml,以及application-{profile}.yml)
绑定配置到 Spring Environment 对象后,发布 ApplicationEnvironmentPreparedEvent(环境准备完成事件)。
步骤 3:打印 Banner
读取项目根目录下的 banner.txt 或默认的 Spring Boot Banner 并打印。无实际业务功能,纯标识作用。
步骤 4:创建 Spring 容器 ApplicationContext
根据步骤 1 判断的应用类型,创建对应的 IOC 容器:
- Servlet Web 应用:创建
AnnotationConfigServletWebServerApplicationContext。 - 非 Web 应用:创建
AnnotationConfigApplicationContext。
原理解析:Web 容器继承自非 Web 容器,额外增加了对 Servlet 环境(如
ServletContext)的支持,并能够管理内嵌 Tomcat 的生命周期。
步骤 5:预处理上下文(前置准备)
给刚创建的空容器做初始化:
- 将
Environment绑定到容器。 - 执行第一阶段加载的所有
ApplicationContextInitializer。 - 发布
ApplicationContextInitializedEvent。 - 将启动类(Main Class)作为配置类注册到容器中。
步骤 6:核心中的核心 —— refresh(context) 刷新容器
这一步是 Spring 容器的灵魂。refresh() 是 AbstractApplicationContext 的模板方法,内部包含 12 个子步骤。Bean 扫描、自动配置、实例化、AOP 全在这里执行。
refresh() 内部 12 步拆解
① prepareRefresh()
- 初始化容器状态(标记为 active)。
- 验证
Environment中配置的必选属性(通过@Value("${xxx:#{null}}"或environment.setRequiredProperties()设置)是否存在。
② obtainFreshBeanFactory()
- 刷新内部
BeanFactory。 - 创建
DefaultListableBeanFactory,这是 Spring IOC 的底层核心实现,后续所有的 Bean 定义和实例都存放在这里。
③ prepareBeanFactory(beanFactory)
- 设置类加载器(ClassLoader)。
- 添加核心的
BeanPostProcessor:ApplicationContextAwareProcessor(用于处理实现了ApplicationContextAware等 Aware 接口的 Bean)。 - 注册默认的环境 Bean(如
environment、systemProperties)。
④ postProcessBeanFactory(beanFactory)
- 空方法,留给子类扩展。
- Web 应用会在这里注册
ServletContextAwareProcessor,处理 Web 相关的 Aware 接口。
⑤ invokeBeanFactoryPostProcessors(beanFactory) 【自动配置核心】
这是自动配置和 Bean 扫描的关键执行点:
- 执行内置的
ConfigurationClassPostProcessor(实现了BeanDefinitionRegistryPostProcessor)。 - 解析启动类上的
@SpringBootApplication,进而解析@ComponentScan,扫描包下所有的@Component/@Service/@Controller。 - 解析
@Configuration和@Bean配置类。 - 自动配置加载:通过
AutoConfigurationImportSelector加载@EnableAutoConfiguration引入的所有自动配置类。 - 根据
@Conditional(如@ConditionalOnClass)条件判断是否将配置类注册为 Bean。 - 将所有解析出的类转化为
BeanDefinition,注册到BeanFactory中。
概念补充:什么是 BeanDefinition?
它不是 Bean 实例,而是 Bean 的“元数据”或“图纸”。它记录了 Bean 的类名、作用域、是否懒加载、依赖关系等信息。Spring 后续会根据这些图纸来实例化 Bean。
⑥ registerBeanPostProcessors(beanFactory)
- 扫描并注册所有的
BeanPostProcessor(Bean 后置处理器)。 - 包括处理
@Autowired的AutowiredAnnotationBeanPostProcessor,处理 AOP 的AnnotationAwareAspectJAutoProxyCreator等。 - 注意区分:
BeanFactoryPostProcessor作用于 Bean 的定义阶段(修改图纸),而BeanPostProcessor作用于 Bean 的实例化阶段(修改成品)。
⑦ initMessageSource()
- 初始化国际化资源(i18n),用于多语言支持。
⑧ initApplicationEventMulticaster()
- 初始化事件广播器。后续容器中发布的所有事件,都由这个广播器分发给对应的 Listener。
⑨ onRefresh() 【内嵌 Tomcat 启动】
- 空方法,留给子类扩展。
- 对于 Web 应用,
ServletWebServerApplicationContext会重写此方法,在这里创建并启动内嵌的 Tomcat/Jetty/Undertow,并初始化DispatcherServlet。
⑩ registerListeners()
- 将所有
ApplicationListener注册到步骤 8 创建的事件广播器中。
⑪ finishBeanFactoryInitialization(beanFactory) 【Bean 实例化核心】
这一步实例化所有非懒加载的单例 Bean,你学过的所有 Bean 原理都在这里:
- 遍历所有
BeanDefinition。 - 调用
getBean()开始创建 Bean。 - 执行 Bean 完整生命周期(详见下方生命周期图)。
- 利用三级缓存解决循环依赖。
- 生成 AOP 代理对象。
- 所有成品 Bean 存入
singletonObjects(一级缓存/单例池)。
⑫ finishRefresh()
- 清除上下文缓存。
- 初始化生命周期处理器(
LifecycleProcessor)。 - 发布
ContextRefreshedEvent(容器刷新完成事件)。 - 正式发布 Web 服务(Tomcat 开始接收外部请求)。
Bean 生命周期与三级缓存时序图
为了更清晰地理解步骤 11 中的 Bean 创建过程,请参考以下时序图:
步骤 7:刷新后处理 postProcessAfterRefresh()
默认空实现,留给子类在容器刷新完成后进行自定义扩展。
步骤 8:停止计时器,打印启动耗时
Started Application in 1.53 seconds (JVM running for 2.1)
步骤 9:执行 ApplicationRunner 与 CommandLineRunner
所有实现了这两个接口的 Bean,会在容器完全启动后、接收外部请求前执行。常用于项目启动后加载字典数据、初始化缓存、校验配置等。
- 执行顺序:可以通过
@Order注解控制。 - 区别:
CommandLineRunner接收原始的String[] args参数;ApplicationRunner接收封装后的ApplicationArguments对象,支持解析--key=value格式的参数。
步骤 10:发布 ApplicationStartedEvent
发布应用已启动成功事件,通知所有监听器。
步骤 11:检查是否有异常
如果启动过程中捕获到异常,发布 ApplicationFailedEvent,并抛出异常终止应用。
步骤 12:返回就绪的 ApplicationContext
启动完成,返回 IOC 容器,应用正式对外提供服务。
核心知识点对应关系表
为了帮你把零散的知识点串联起来,请参考下表:
| 启动步骤 | 对应核心原理 / 面试考点 |
|---|---|
| 构造器初始化 | Spring SPI 机制(spring.factories / .imports)、应用类型推断 |
| prepareEnvironment | 配置加载优先级、多环境配置(Profiles)原理 |
| invokeBeanFactoryPostProcessors | 自动配置原理(@EnableAutoConfiguration)、@Conditional 条件注解、BeanDefinition 概念 |
| registerBeanPostProcessors | BeanPostProcessor 与 BeanFactoryPostProcessor 的区别、AOP 处理器注册 |
| onRefresh | 内嵌 Tomcat 启动原理、Spring Boot 为什么不需要外部部署 |
| finishBeanFactoryInitialization | Bean 生命周期、三级缓存解决循环依赖、AOP 动态代理生成时机 |
| 执行 Runner | ApplicationRunner 与 CommandLineRunner 的使用场景与区别 |
总结
白话文通俗总结(最易记忆)
- 认清身份:先搞清楚自己是 Web 应用还是普通应用。
- 准备粮草:加载所有配置(yml、命令行、环境变量)。
- 建好空房:创建一个空的 IOC 容器。
- 绘制图纸:扫描所有 Bean 和自动配置(SPI),生成 BeanDefinition。
- 准备工具:注册所有 Bean 后置处理器(准备处理 Autowired、AOP、事务)。
- 启动引擎:启动内嵌 Tomcat。
- 生产产品:批量实例化所有单例 Bean,走生命周期、解决循环依赖、生成 AOP 代理。
- 收尾工作:执行启动后的回调 Runner。
- 开门迎客:发布启动成功事件,服务正式就绪。
面试高频“一句话总结”
“SpringBoot 启动就是:先准备 Environment 环境,再创建 IOC 容器;通过 SPI 机制加载自动配置类并扫描组件生成 BeanDefinition;接着注册 BeanPostProcessor;然后在
onRefresh中启动内嵌 Tomcat;最后在finishBeanFactoryInitialization中批量实例化单例 Bean,期间通过三级缓存解决循环依赖并生成 AOP 代理,最终发布启动成功事件对外提供服务。”
掌握以上流程,不仅能让你在面试中对答如流,在遇到 BeanCreationException、CircularReference 或自动配置失效等启动报错时,也能迅速定位到是哪个阶段、哪个后置处理器出了问题。
更多推荐

所有评论(0)