SpringBoot 优雅停机实现原理与最佳实践指南

 更新时间:2026年04月20日 09:32:09   作者:程序员1970  
文章介绍了Spring Boot在2.3版本中引入的优雅停机机制,详细解释了优雅停机的概念、核心组件与层级关系、Spring Boot 2.3前后的区别,以及在生产环境中的最佳实践,强调了启用优雅停机的重要性,以提高系统的高可用性和稳定性

微服务和云原生时代,应用的平滑启停是保障系统高可用的关键环节。Spring Boot 在 2.3 版本引入了对内嵌 Web 容器优雅停机的原生支持,改变此前需要手动编码实现局面。

一、什么是“优雅停机”?

优雅停机(Graceful Shutdown) 是指在应用停止过程中:

  1. 立即停止接收新请求
  2. 允许已进入的请求继续处理完成
  3. 安全释放资源(数据库连接、线程池、缓存等);
  4. 避免客户端收到 5xx 错误或连接中断

若未实现优雅停机,在滚动更新、缩容或重启时,极易出现如下典型异常:

ERROR ... - Error creating bean with name 'orderController': 
Singleton bean creation not allowed while singletons of this factory are in destruction
org.springframework.beans.factory.BeanCreationNotAllowedException: ...

异常表明:Spring 容器正在销毁,但仍有请求试图获取 Controller Bean —— 这正是停机流程设计不当的直接体现。

二、核心组件与层级关系

要理解停机流程,需先厘清以下组件的包含关系:

JVM
 └── 内嵌 Web 容器(如 Tomcat)
      └── Servlet 容器(StandardContext)
           └── DispatcherServlet(Spring MVC 入口)
                └── Spring ApplicationContext(IoC 容器)
                     └── 所有 Spring Bean(@Controller, @Service 等)
  • Web 容器(Tomcat/Jetty/Undertow):负责网络连接与线程调度。
  • Servlet 容器:管理 Servlet、Filter 生命周期。
  • Spring 容器:即 ApplicationContext,管理 Bean 的创建与销毁。
  • Spring Boot不是容器,而是自动集成 Web 容器 + Spring 容器的启动框架。

⚠️ 关键点:Spring 容器运行在 Web 容器内部。停机时,必须协调二者关闭顺序,否则就会出现“Web 容器还在处理请求,但 Spring 容器已拒绝服务”的竞态条件。

三、Spring Boot < 2.3:手动实现的“伪优雅”

在2.3之前,Spring Boot 没有内置优雅停机能力。默认行为是:

  1. 收到 SIGTERM(如 kill -15);
  2. 立即关闭 Spring 容器 → 设置 singletonsCurrentlyInDestruction = true
  3. Web 容器仍在运行,继续 accept 新连接并分配线程;
  4. 若此时有请求进入,DispatcherServlet 尝试通过 getBean("orderController") 获取 Controller;
  5. 因 Spring 容器已标记为“销毁中”,抛出 BeanCreationNotAllowedException

❌ 问题本质:关闭顺序错误

先关 Spring,再关 Web 容器 → 存在危险时间窗口。

🛠️ 开发者workaround

需手动实现以下逻辑:

@Component
public class GracefulShutdown implements TomcatConnectorCustomizer, 
                                      ApplicationListener<ContextClosedEvent> {
    private volatile Connector connector;
    @Override
    public void customize(Connector connector) {
        this.connector = connector;
    }
    @Override
    public void onApplicationEvent(ContextClosedEvent event) {
        connector.pause(); // 停止接收新请求
        Executor executor = connector.getProtocolHandler().getExecutor();
        if (executor instanceof ThreadPoolExecutor) {
            try {
                ((ThreadPoolExecutor) executor).shutdown();
                ((ThreadPoolExecutor) executor).awaitTermination(30, TimeUnit.SECONDS);
            } catch (InterruptedException e) {
                Thread.currentThread().interrupt();
            }
        }
    }
}

同时需注册到 Tomcat:

@Bean
public ServletWebServerFactory servletContainer() {
    TomcatServletWebServerFactory tomcat = new TomcatServletWebServerFactory();
    tomcat.addConnectorCustomizers(gracefulShutdown());
    return tomcat;
}

💡 即便如此,仍无法完美处理 HTTP/1.1 keep-alive 连接复用带来的新请求。

四、Spring Boot ≥ 2.3:原生优雅停机

Spring Boot 2.3 引入了 标准化的优雅停机机制,通过两行配置即可启用:

server:
  shutdown: graceful          # 启用优雅停机
spring:
  lifecycle:
    timeout-per-shutdown-phase: 30s  # 等待超时时间

✅ 核心思想:反转关闭顺序 + 流量控制前置

停机流程变为:

  1. Web 容器立即 pause:停止 accept 新连接(Tomcat 调用 connector.pause());
  2. 等待已进入的请求完成:最多等待 timeout-per-shutdown-phase 时间;
  3. 确认无活跃请求后,关闭 Spring 容器:销毁所有 Bean;
  4. 彻底停止 Web 容器线程池

🧠 底层原理

1.SmartLifecycle控制关闭阶段

Spring Boot 注册了 WebServerGracefulShutdownLifecycle,它实现 SmartLifecycle 接口,并设置:

@Override
public int getPhase() {
    return Integer.MAX_VALUE; // 最后启动,最先停止
}

确保其 stop() 方法在普通 Bean 销毁之前执行。

2.WebServer 接口标准化

不同内嵌服务器实现统一的 GracefulShutdown 行为:

  • Tomcatpause() + 等待线程池
  • Jetty:停止 acceptor 线程
  • Undertow:返回 503 给新请求
  • Reactor Netty:发送 GOAWAY(HTTP/2)

3.与 Spring 生命周期深度集成

通过 LifecycleProcessor 协调所有 SmartLifecycle Bean 的关闭顺序,确保 Web 容器优雅关闭完成之后,才触发 ApplicationContext.close()

五、2.3 前后对比总表

维度Spring Boot < 2.3Spring Boot ≥ 2.3
是否内置支持❌ 需手动编码✅ 开箱即用
关闭起点Spring 容器Web 容器
新请求处理继续 accept → 高风险立即拒绝(pause/503)→ 安全
已进入请求可能因 Spring 关闭而失败等待完成(最多 timeout)
典型异常BeanCreationNotAllowedException 高频极少(除非超时)
配置复杂度高(需自定义监听器)低(仅需 YAML)
多容器支持仅限手动适配自动支持 Tomcat/Jetty/Undertow/Netty
K8s 友好度优秀

六、生产环境最佳实践

1.启用优雅停机(2.3+)

server:
  shutdown: graceful
spring:
  lifecycle:
    timeout-per-shutdown-phase: 45s  # > 业务最大请求耗时

2.Kubernetes 部署配合 preStop

spec:
  containers:
    - name: app
      lifecycle:
        preStop:
          exec:
            command: ["sleep", "15"]  # 给 LB 时间摘除节点
      terminationGracePeriodSeconds: 60

3.Windows 服务需走 Actuator

management:
  endpoint:
    shutdown:
      enabled: true
  endpoints:
    web:
      exposure:
        include: "shutdown"

并通过外部命令触发:

curl -X POST http://localhost:8080/actuator/shutdown

4.监控与告警

  • 监控停机期间的 5xx 错误率;
  • 若仍有 BeanCreationNotAllowedException,检查:
    • 超时时间是否足够;
    • LB 摘除延迟;
    • 是否存在长轮询/WebSocket 未处理。

🌟 一句话建议:
只要你的Spring Boot 版本 ≥ 2.3,务必启用 server.shutdown=graceful,并配合基础设施实现流量摘除。这能显著提升系统在滚动更新、弹性伸缩场景下的稳定性与用户体验。

到此这篇关于SpringBoot 优雅停机实现原理与最佳实践指南的文章就介绍到这了,更多相关SpringBoot 优雅停机内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

相关文章

  • springBoot整合redis做缓存具体操作步骤

    springBoot整合redis做缓存具体操作步骤

    缓存主要是将数据存在计算机的内存当中,以便于在使用的时候是可以实现快速读取使用,它的快也是相对于硬盘读取而言,这篇文章主要给大家介绍了关于springBoot整合redis做缓存的具体操作步骤,需要的朋友可以参考下
    2024-04-04
  • Java使用JSQLParser解析和操作SQL的技术指南

    Java使用JSQLParser解析和操作SQL的技术指南

    在开发过程中,解析和操作 SQL 是一个常见的需求,JSQLParser 是一个强大的开源 Java 库,用于解析 SQL 并提供语法树操作功能,本文将详细介绍如何使用 JSQLParser,并提供常见使用场景的代码示例,需要的朋友可以参考下
    2025-04-04
  • 深入剖析ArrayList的remove方法

    深入剖析ArrayList的remove方法

    这篇文章主要介绍了ArrayList的remove方法使用,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教。</p>
    2021-09-09
  • Java实现小型图书馆管理系统

    Java实现小型图书馆管理系统

    这篇文章主要为大家详细介绍了Java实现小型图书馆管理系统,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2020-11-11
  • JAVA中compareTo方法的使用小结

    JAVA中compareTo方法的使用小结

    compareTo方法的目的是用来比较两个对象的大小的,本文主要介绍了JAVA中compareTo方法的使用小结,具有一定的参考价值,感兴趣的可以了解一下
    2024-07-07
  • java垃圾回收之实现并行GC算法

    java垃圾回收之实现并行GC算法

    这篇文章主要为大家介绍了java垃圾回收之实现并行GC算法的详细讲解,让我们看看并行垃圾收集器的GC日志长什么样, 从中我们可以得到哪些有用信息
    2022-01-01
  • 浅析SpringBoot统一返回结果的实现

    浅析SpringBoot统一返回结果的实现

    前后端开发过程中数据交互规范化是一件非常重要的事情,不仅可以减少前后端交互过程中出现的问题,也让代码逻辑更加具有条理,下面小编就和大家讲讲SpringBoot如何统一返回结果的吧
    2023-07-07
  • SpringCloud之Zuul网关原理及其配置讲解

    SpringCloud之Zuul网关原理及其配置讲解

    这篇文章主要介绍了SpringCloud之Zuul网关原理及其配置讲解,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教
    2022-03-03
  • java使用GeoTools读取shp文件并画图的操作代码

    java使用GeoTools读取shp文件并画图的操作代码

    GeoTools是ArcGis地图与java对象的桥梁,今天通过本文给大家分享java使用GeoTools读取shp文件并画图,文章通过实例代码给大家介绍的非常详细,需要的朋友参考下吧
    2021-07-07
  • Java中ReentrantLock的用法和原理

    Java中ReentrantLock的用法和原理

    本文主要介绍了Java中ReentrantLock的用法和原理,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2023-06-06

最新评论