SpringBoot 启动流程全解析:从源码到面试,一文打通 Bean 生命周期与自动配置
本文将按照真实源码的执行顺序,把 SpringBoot 启动流程、Bean 生命周期、三级缓存、自动配置、SPI 机制、BeanPostProcessor 等核心知识点全部串联起来。无论是应对面试,还是日常排查启动报错,这篇文章都能为你提供清晰的思路。
整体总览:SpringBoot 启动的两大阶段
SpringBoot 的启动过程本质上可以分为两大阶段:
入口代码永远是这一行:
@SpringBootApplication
public class Application {
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
}
全局启动流程图
#mermaid-svg-KyWVnsCSaOFNGNOj{font-family:\”trebuchet ms\”,verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-KyWVnsCSaOFNGNOj .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-KyWVnsCSaOFNGNOj .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-KyWVnsCSaOFNGNOj .error-icon{fill:#552222;}#mermaid-svg-KyWVnsCSaOFNGNOj .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-KyWVnsCSaOFNGNOj .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-KyWVnsCSaOFNGNOj .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-KyWVnsCSaOFNGNOj .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-KyWVnsCSaOFNGNOj .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-KyWVnsCSaOFNGNOj .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-KyWVnsCSaOFNGNOj .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-KyWVnsCSaOFNGNOj .marker{fill:#333333;stroke:#333333;}#mermaid-svg-KyWVnsCSaOFNGNOj .marker.cross{stroke:#333333;}#mermaid-svg-KyWVnsCSaOFNGNOj svg{font-family:\”trebuchet ms\”,verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-KyWVnsCSaOFNGNOj p{margin:0;}#mermaid-svg-KyWVnsCSaOFNGNOj .label{font-family:\”trebuchet ms\”,verdana,arial,sans-serif;color:#333;}#mermaid-svg-KyWVnsCSaOFNGNOj .cluster-label text{fill:#333;}#mermaid-svg-KyWVnsCSaOFNGNOj .cluster-label span{color:#333;}#mermaid-svg-KyWVnsCSaOFNGNOj .cluster-label span p{background-color:transparent;}#mermaid-svg-KyWVnsCSaOFNGNOj .label text,#mermaid-svg-KyWVnsCSaOFNGNOj span{fill:#333;color:#333;}#mermaid-svg-KyWVnsCSaOFNGNOj .node rect,#mermaid-svg-KyWVnsCSaOFNGNOj .node circle,#mermaid-svg-KyWVnsCSaOFNGNOj .node ellipse,#mermaid-svg-KyWVnsCSaOFNGNOj .node polygon,#mermaid-svg-KyWVnsCSaOFNGNOj .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-KyWVnsCSaOFNGNOj .rough-node .label text,#mermaid-svg-KyWVnsCSaOFNGNOj .node .label text,#mermaid-svg-KyWVnsCSaOFNGNOj .image-shape .label,#mermaid-svg-KyWVnsCSaOFNGNOj .icon-shape .label{text-anchor:middle;}#mermaid-svg-KyWVnsCSaOFNGNOj .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-KyWVnsCSaOFNGNOj .rough-node .label,#mermaid-svg-KyWVnsCSaOFNGNOj .node .label,#mermaid-svg-KyWVnsCSaOFNGNOj .image-shape .label,#mermaid-svg-KyWVnsCSaOFNGNOj .icon-shape .label{text-align:center;}#mermaid-svg-KyWVnsCSaOFNGNOj .node.clickable{cursor:pointer;}#mermaid-svg-KyWVnsCSaOFNGNOj .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-KyWVnsCSaOFNGNOj .arrowheadPath{fill:#333333;}#mermaid-svg-KyWVnsCSaOFNGNOj .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-KyWVnsCSaOFNGNOj .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-KyWVnsCSaOFNGNOj .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-KyWVnsCSaOFNGNOj .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-KyWVnsCSaOFNGNOj .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-KyWVnsCSaOFNGNOj .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-KyWVnsCSaOFNGNOj .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-KyWVnsCSaOFNGNOj .cluster text{fill:#333;}#mermaid-svg-KyWVnsCSaOFNGNOj .cluster span{color:#333;}#mermaid-svg-KyWVnsCSaOFNGNOj div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:\”trebuchet ms\”,verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-KyWVnsCSaOFNGNOj .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-KyWVnsCSaOFNGNOj rect.text{fill:none;stroke-width:0;}#mermaid-svg-KyWVnsCSaOFNGNOj .icon-shape,#mermaid-svg-KyWVnsCSaOFNGNOj .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-KyWVnsCSaOFNGNOj .icon-shape p,#mermaid-svg-KyWVnsCSaOFNGNOj .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-KyWVnsCSaOFNGNOj .icon-shape .label rect,#mermaid-svg-KyWVnsCSaOFNGNOj .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-KyWVnsCSaOFNGNOj .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-KyWVnsCSaOFNGNOj .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-KyWVnsCSaOFNGNOj :root{–mermaid-font-family:\”trebuchet ms\”,verdana,arial,sans-serif;}
main方法启动
第一阶段: new SpringApplication
推断应用类型 Web/None
加载 ApplicationContextInitializer
加载 ApplicationListener
推断主类 MainApplicationClass
第二阶段: 执行 run 方法
启动计时器 & 获取监听器
准备 Environment 环境
打印 Banner
创建 ApplicationContext 容器
预处理上下文
核心: refresh 刷新容器
刷新后处理 & 停止计时
执行 Runner 回调
发布启动完成事件
第一阶段: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
这一步加载所有配置,是整个应用的配置来源。加载顺序决定了配置的优先级(优先级从高到低):
绑定配置到 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:预处理上下文(前置准备)
给刚创建的空容器做初始化:
步骤 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 扫描的关键执行点:
概念补充:什么是 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 原理都在这里:
⑫ finishRefresh()
- 清除上下文缓存。
- 初始化生命周期处理器(LifecycleProcessor)。
- 发布 ContextRefreshedEvent(容器刷新完成事件)。
- 正式发布 Web 服务(Tomcat 开始接收外部请求)。
Bean 生命周期与三级缓存时序图
为了更清晰地理解步骤 11 中的 Bean 创建过程,请参考以下时序图:
BeanPostProcessor
目标 Bean
BeanFactory
Spring 容器
BeanPostProcessor
目标 Bean
BeanFactory
Spring 容器
#mermaid-svg-wC0eUi2kYJJ1sP0L{font-family:\”trebuchet ms\”,verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-wC0eUi2kYJJ1sP0L .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-wC0eUi2kYJJ1sP0L .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-wC0eUi2kYJJ1sP0L .error-icon{fill:#552222;}#mermaid-svg-wC0eUi2kYJJ1sP0L .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-wC0eUi2kYJJ1sP0L .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-wC0eUi2kYJJ1sP0L .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-wC0eUi2kYJJ1sP0L .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-wC0eUi2kYJJ1sP0L .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-wC0eUi2kYJJ1sP0L .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-wC0eUi2kYJJ1sP0L .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-wC0eUi2kYJJ1sP0L .marker{fill:#333333;stroke:#333333;}#mermaid-svg-wC0eUi2kYJJ1sP0L .marker.cross{stroke:#333333;}#mermaid-svg-wC0eUi2kYJJ1sP0L svg{font-family:\”trebuchet ms\”,verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-wC0eUi2kYJJ1sP0L p{margin:0;}#mermaid-svg-wC0eUi2kYJJ1sP0L .actor{stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);fill:#ECECFF;}#mermaid-svg-wC0eUi2kYJJ1sP0L text.actor>tspan{fill:black;stroke:none;}#mermaid-svg-wC0eUi2kYJJ1sP0L .actor-line{stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);}#mermaid-svg-wC0eUi2kYJJ1sP0L .innerArc{stroke-width:1.5;stroke-dasharray:none;}#mermaid-svg-wC0eUi2kYJJ1sP0L .messageLine0{stroke-width:1.5;stroke-dasharray:none;stroke:#333;}#mermaid-svg-wC0eUi2kYJJ1sP0L .messageLine1{stroke-width:1.5;stroke-dasharray:2,2;stroke:#333;}#mermaid-svg-wC0eUi2kYJJ1sP0L #arrowhead path{fill:#333;stroke:#333;}#mermaid-svg-wC0eUi2kYJJ1sP0L .sequenceNumber{fill:white;}#mermaid-svg-wC0eUi2kYJJ1sP0L #sequencenumber{fill:#333;}#mermaid-svg-wC0eUi2kYJJ1sP0L #crosshead path{fill:#333;stroke:#333;}#mermaid-svg-wC0eUi2kYJJ1sP0L .messageText{fill:#333;stroke:none;}#mermaid-svg-wC0eUi2kYJJ1sP0L .labelBox{stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);fill:#ECECFF;}#mermaid-svg-wC0eUi2kYJJ1sP0L .labelText,#mermaid-svg-wC0eUi2kYJJ1sP0L .labelText>tspan{fill:black;stroke:none;}#mermaid-svg-wC0eUi2kYJJ1sP0L .loopText,#mermaid-svg-wC0eUi2kYJJ1sP0L .loopText>tspan{fill:black;stroke:none;}#mermaid-svg-wC0eUi2kYJJ1sP0L .loopLine{stroke-width:2px;stroke-dasharray:2,2;stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);fill:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);}#mermaid-svg-wC0eUi2kYJJ1sP0L .note{stroke:#aaaa33;fill:#fff5ad;}#mermaid-svg-wC0eUi2kYJJ1sP0L .noteText,#mermaid-svg-wC0eUi2kYJJ1sP0L .noteText>tspan{fill:black;stroke:none;}#mermaid-svg-wC0eUi2kYJJ1sP0L .activation0{fill:#f4f4f4;stroke:#666;}#mermaid-svg-wC0eUi2kYJJ1sP0L .activation1{fill:#f4f4f4;stroke:#666;}#mermaid-svg-wC0eUi2kYJJ1sP0L .activation2{fill:#f4f4f4;stroke:#666;}#mermaid-svg-wC0eUi2kYJJ1sP0L .actorPopupMenu{position:absolute;}#mermaid-svg-wC0eUi2kYJJ1sP0L .actorPopupMenuPanel{position:absolute;fill:#ECECFF;box-shadow:0px 8px 16px 0px rgba(0,0,0,0.2);filter:drop-shadow(3px 5px 2px rgb(0 0 0 / 0.4));}#mermaid-svg-wC0eUi2kYJJ1sP0L .actor-man line{stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);fill:#ECECFF;}#mermaid-svg-wC0eUi2kYJJ1sP0L .actor-man circle,#mermaid-svg-wC0eUi2kYJJ1sP0L line{stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);fill:#ECECFF;stroke-width:2px;}#mermaid-svg-wC0eUi2kYJJ1sP0L :root{–mermaid-font-family:\”trebuchet ms\”,verdana,arial,sans-serif;}
若发现循环依赖,从三级缓存获取早期引用,
并移入二级缓存 (earlySingletonObjects)
AOP 代理在此阶段生成
getBean("targetBean")
1. 实例化 Bean (调用构造器)
2. 将 ObjectFactory 放入三级缓存 (singletonFactories)
3. 属性填充 (populateBean)
4. 调用 Aware 接口方法 (BeanNameAware 等)
5. 初始化前 (postProcessBeforeInitialization)
返回处理后的 Bean
6. 执行初始化方法 (@PostConstruct, InitializingBean, init-method)
7. 初始化后 (postProcessAfterInitialization)
返回代理对象或原对象
8. 将最终成品放入一级缓存 (singletonObjects)
9. 清理二级、三级缓存
返回最终的 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 的使用场景与区别 |
总结
白话文通俗总结(最易记忆)
面试高频“一句话总结”
“SpringBoot 启动就是:先准备 Environment 环境,再创建 IOC 容器;通过 SPI 机制加载自动配置类并扫描组件生成 BeanDefinition;接着注册 BeanPostProcessor;然后在 onRefresh 中启动内嵌 Tomcat;最后在 finishBeanFactoryInitialization 中批量实例化单例 Bean,期间通过三级缓存解决循环依赖并生成 AOP 代理,最终发布启动成功事件对外提供服务。”
掌握以上流程,不仅能让你在面试中对答如流,在遇到 BeanCreationException、CircularReference 或自动配置失效等启动报错时,也能迅速定位到是哪个阶段、哪个后置处理器出了问题。



