Spring Boot 启动流程与生命周期详解

Spring Boot 启动流程与生命周期详解

定位:第 07 篇,讲透 SpringApplication 启动全流程、各启动事件与扩展点、启动后任务、优雅停机

适用版本:Spring Boot 3.x(JDK 17+)

前置:容器 refresh 流程见 FW-01篇


目录


一、启动入口

SpringApplication.run() 分两个阶段:

1.1 构造阶段(准备)

复制代码
new SpringApplication(primarySources)
├── 推断应用类型:SERVLET / REACTIVE / NONE(按 classpath 判断)
├── 加载 ApplicationContextInitializer(从 imports/spring.factories)
├── 加载 ApplicationListener
└── 推断主应用类(main 所在类)

应用类型推断 决定了用哪种 ApplicationContext:Servlet 应用用 ServletWebServerApplicationContext(内嵌容器),响应式用 ReactiveWebServerApplicationContext。

1.2 run 阶段(执行)

依次执行启动步骤并在关键点发布事件(第二节)。核心骨架:

复制代码
① 启动计时,创建引导上下文
② 准备环境(Environment):加载配置、应用 profile
③ 创建 ApplicationContext(按应用类型)
④ 准备上下文:注册主配置类、执行 Initializer
⑤ 刷新上下文 refresh():组件扫描、自动配置、实例化单例、起内嵌容器
⑥ 刷新后处理 + 执行 Runner
⑦ 发布 ApplicationReadyEvent

二、启动步骤与事件

事件是启动流程的"观测点",按序发布:

事件 时机 可做什么
ApplicationStartingEvent 刚启动,任何处理前 最早的钩子
ApplicationEnvironmentPreparedEvent 环境就绪、配置已加载 依据配置做决策
ApplicationContextInitializedEvent 上下文创建、Initializer 执行后 ---
ApplicationPreparedEvent Bean 定义已加载,未刷新 注册额外 Bean
ContextRefreshedEvent 容器刷新完成(单例就绪) 框架级初始化(FW-01)
ApplicationStartedEvent 启动完成、Runner 未跑 ---
ApplicationReadyEvent 完全就绪,可接收请求 业务就绪动作 ★
ContextClosedEvent 关闭前 清理资源

记忆锚点:EnvironmentPrepared 是配置就绪,Refreshed 是容器就绪,Ready 是可接流量。


三、扩展点

3.1 ApplicationContextInitializer

在上下文 refresh() 之前对上下文编程式定制(注册属性源、激活 profile、注册 Bean):

java 复制代码
public class CustomInitializer implements ApplicationContextInitializer<ConfigurableApplicationContext> {
    public void initialize(ConfigurableApplicationContext ctx) { /* 刷新前定制 */ }
}

3.2 ApplicationListener

监听第二节各事件,把自定义逻辑挂到启动/关闭的精确时点(如 Ready 时预热缓存)。

3.3 启动后一次性任务(高频)

java 复制代码
@Component
public class WarmupRunner implements ApplicationRunner {   // 或 CommandLineRunner
    public void run(ApplicationArguments args) {
        // 容器就绪后执行一次:预热缓存、数据初始化、自检
    }
}
接口 参数
CommandLineRunner 原始 String\[\]
ApplicationRunner 封装的 ApplicationArguments(解析命名参数)

用 @Order 控制多个 Runner 顺序;Runner 抛异常会导致启动失败(适合做"启动自检")。

3.4 注册扩展的方式

ApplicationContextInitializer/ApplicationListener 可通过 AutoConfiguration.imports/spring.factories、SpringApplicationBuilder、spring.properties 声明;Runner 直接 @Component 即可。


四、优雅停机

4.1 停机触发与流程

复制代码
SIGTERM(kill)/ shutdown 端点 / context.close()
   ▼
① server.shutdown=graceful:Web 容器停止接收新请求,等待在途请求(超时上限内)
② 发布 ContextClosedEvent → 监听器清理(停定时任务、关连接池)
③ 销毁单例(@PreDestroy 等,FW-01)
④ 关闭容器,进程退出

4.2 配合无损下线

复制代码
发布流程(呼应无损上下线):
   负载均衡摘流 → 宽限等待 → 优雅停机(等在途)→ 进程退出

仅靠优雅停机不够------已建立的客户端连接在途请求需要摘流先行。


五、总结

  1. 两阶段启动:构造期推断应用类型并加载 Initializer/Listener;run 期准备环境 → 建上下文 → refresh(起容器、实例化单例)→ 跑 Runner → Ready。
  2. 事件序列 :Starting → EnvironmentPrepared → ...Prepared → Refreshed → Started → Ready(可接流量);是挂钩启动逻辑的观测点。
  3. 扩展点:Initializer(刷新前定制)、Listener(事件挂钩)、ApplicationRunner/CommandLineRunner(启动后一次性任务,可做自检)。
  4. 优雅停机:graceful 停接新请求等在途 + ContextClosedEvent 清理 + Bean 销毁;配合摘流实现无损下线。

六、常见高频面试题

1. 详细描述 Spring Boot 的启动流程。

要点:SpringApplication.run 两阶段。构造阶段:推断应用类型(Servlet/Reactive)、加载 ApplicationContextInitializer 与 ApplicationListener。run 阶段:创建并准备 Environment(加载配置、激活 profile)→ 按类型创建 ApplicationContext → 准备上下文(注册主配置、执行 Initializer)→ refresh(组件扫描、自动配置、实例化非懒加载单例、启动内嵌容器)→ 执行 Runner → 发布 ApplicationReadyEvent。全程伴随启动事件发布。

2. SpringApplication 如何推断应用类型?

要点:按 classpath 判断------存在 Servlet 相关类(如 jakarta.servlet.Servlet + Spring 的 DispatcherServlet)判为 SERVLET,用 ServletWebServerApplicationContext;存在 Spring WebFlux 的 DispatcherHandler 且无 Servlet 判为 REACTIVE;否则 NONE(普通上下文)。这决定了容器类型与 Web 栈。也可通过 setWebApplicationType 显式指定。

3. ApplicationReadyEvent 和 ContextRefreshedEvent 的区别?

要点:ContextRefreshedEvent 在容器刷新完成(所有单例实例化、内嵌容器启动)时发布,是 Framework 层的就绪信号;ApplicationReadyEvent 是 Boot 层信号,在 Runner 执行后发布,表示应用完全就绪、可以接收外部请求。业务"启动后动作"(预热、注册服务、开始消费)推荐监听 Ready;框架级初始化可用 Refreshed。

4. CommandLineRunner 和 ApplicationRunner 的区别与用途?

要点:都在容器就绪后执行一次性任务,都可用 @Order 控制顺序。区别在参数:CommandLineRunner 接收原始 String\[\],ApplicationRunner 接收封装的 ApplicationArguments(可解析 --name=value 命名参数,更友好)。用途:数据初始化、缓存预热、启动自检(抛异常可让启动失败,健康防线)。注意它们运行一次,不是定时任务。

5. ApplicationContextInitializer 有什么用?

要点:在 ApplicationContext refresh() 之前编程式定制上下文的钩子------如动态激活 profile、注册属性源、注册额外 Bean、调整上下文行为。通过 spring.factories/imports、SpringApplicationBuilder 或配置注册。典型场景:根据环境变量注入配置源、测试时替换上下文实现。它在生命周期极早期生效,早于 Bean 定义加载。

6. Spring Boot 如何实现优雅停机?

要点:配置 server.shutdown=graceful 后,收到停机信号(SIGTERM/close)时 Web 容器停止接收新请求,等待在途请求完成(超时由 spring.lifecycle.timeout-per-shutdown-phase 控制),同时发布 ContextClosedEvent 让监听器清理资源(停定时任务、关连接),再销毁单例执行 @PreDestroy,最后退出。配合负载均衡摘流与宽限期实现发布零中断。

7. 启动事件有哪些?分别什么时候触发?

要点:按时序------ApplicationStartingEvent(刚启动)→ ApplicationEnvironmentPreparedEvent(环境/配置就绪)→ ApplicationContextInitializedEvent(Initializer 执行后)→ ApplicationPreparedEvent(Bean 定义加载、未刷新)→ ContextRefreshedEvent(容器刷新、单例就绪)→ ApplicationStartedEvent(启动完成)→ ApplicationReadyEvent(可接请求);关闭时 ContextClosedEvent。是挂载启动/关闭逻辑的精确钩子。

8. 为什么"启动自检"建议放在 Runner 里并让失败阻断启动?

要点:关键依赖(配置、下游连通、必要数据)若缺失,宁可启动失败(快速失败)也不要带病上线接流量造成更大故障。Runner 在容器就绪后执行、能拿到全部 Bean,抛异常会使启动失败------适合做自检(探下游、校验配置完整性)。配合部署系统的健康检查与回滚,形成"起不来就不接流量"的保护。

9. 应用启动很慢,如何分析和优化?

要点:分析:观察启动日志各阶段耗时(Boot 会输出启动时间与阶段);开条件评估与 Bean 初始化耗时(如 ApplicationStartup 的 BufferingApplicationStartup + Actuator 或 startup 端点)。优化:缩小组件扫描范围、重资源 Bean 改 @Lazy、排除不需要的自动配置(减少条件评估与装配)、减少启动期同步初始化(移到 Runner 异步或按需)。目标:缩短就绪时间,加快弹性伸缩。

10. Boot 应用关闭时,各资源的关闭顺序是怎样的?

要点:大致逆序。① Web 容器先停接新请求(若开优雅停机则在途请求等待);② 发布 ContextClosedEvent,监听器执行清理(停调度、关消费者);③ 销毁单例:执行 @PreDestroy、DisposableBean、destroy-method(FW-01 销毁回调顺序);④ 关闭 ApplicationContext 与底层资源(连接池等)。要点:关闭是"先停入口、再清任务、后毁资源",自定义资源应通过 DisposableBean/@PreDestroy 或监听 ContextClosedEvent 纳入统一管理。

相关推荐
小蒜学长10 小时前
基于SpringBoot的公寓报修管理系统的设计与实现(代码+数据库+LW)
java·spring boot·后端·公寓报修管理系统·多角色协同
十年Java程序媛18 小时前
final 别乱用!变量、方法、类的区别,90% 新手混淆
java·spring boot
念越19 小时前
初中语数英答题与竞赛平台
java·数据库·spring boot
imDwAaY21 小时前
Spring中过滤器和拦截器的区别是什么?
spring boot·后端·spring
萧瑟余晖1 天前
Spring Boot Web开发与内嵌容器详解
spring boot
Q26433650231 天前
【有源码】基于Spring Boot和Vue的在线考试与交流系统-教育信息化背景下在线考试与交流一体化平台
java·vue.js·spring boot·mysql·spring·毕业设计·课程设计
EatFan1 天前
2026 后端 AI 集成三条落地路径:Spring AI 2.0、MCP 协议与旁路服务怎么选
java·人工智能·spring boot·spring·大模型·spring ai·mcp
imDwAaY1 天前
Spring Boot的核心配置文件一览及其加载顺序
java·spring boot·后端