Spring Boot 实现程序的优雅退出(详细步骤)

 更新时间:2024年03月19日 10:07:38   作者:牵着猫散步的鼠鼠  
Spring Boot 为我们提供了优雅退出的功能,使应用程序能够在关闭时正常处理完所有当前请求,避免请求被中断导致数据丢失或不一致等问题,本文将全面介绍如何在 Spring Boot 应用程序中实现优雅退出,感兴趣的朋友跟随小编一起看看吧

前言

在服务器环境中,确保应用程序能够平滑关闭并处理完所有现有请求是一个重要的需求。Spring Boot 为我们提供了优雅退出的功能,使应用程序能够在关闭时正常处理完所有当前请求,避免请求被中断导致数据丢失或不一致等问题。本文将全面介绍如何在 Spring Boot 应用程序中实现优雅退出。

优雅停机是什么

优雅停机(Graceful Shutdown) 是指在服务器需要关闭或重启时,能够先处理完当前正在进行的请求,然后再停止服务的操作。

优雅停机的实现步骤主要分为以下几步:

  • 停止接收新的请求:首先,系统会停止接受新的请求,这样就不会有新的任务被添加到任务队列中。
  • 处理当前请求:系统会继续处理当前已经在处理中的请求,确保这些请求能够正常完成。这通常涉及到等待正在执行的任务完成,如处理HTTP请求、数据库操作等。
  • 释放资源:在请求处理完成后,系统会释放所有已分配的资源,如关闭数据库连接、断开网络连接等。
  • 关闭服务:最后,当所有请求都处理完毕且资源都已释放后,系统会安全地关闭服务。

SpringBoot如何实现优雅停机

优雅停机的实现步骤分为以下两步:

  • 使用合理的 kill 命令,给 Spring Boot 项目发送优雅停机指令。
  • 开启 Spring Boot 优雅停机/自定义 Spring Boot 优雅停机的实现。

合理杀死进程

在 Linux 中 kill 杀死进程的常用命令有以下这些:

  • kill -2 pid:向指定 pid 发送 SIGINT 中断信号,等同于 ctrl+c。也就说,不仅当前进程会收到该信号,而且它的子进程也会收到终止的命令。
  • kill -9 pid:向指定 pid 发送 SIGKILL 立即终止信号。程序不能捕获该信号,最粗暴最快速结束程序的方法。
  • kill -15 pid:向指定 pid 发送 SIGTERM 终止信号。信号会被当前进程接收到,但它的子进程不会收到,如果当前进程被 kill 掉,它的的子进程的父进程将变成 init 进程 (init 进程是那个 pid 为 1 的进程)。
  • kill pid:等同于 kill 15 pid。

因此,在以上命令中,我们不能使用“kill -9”来杀死进程,使用“kill”杀死进程即可

法一:配置设置SpringBoot优雅停机

在 Spring Boot 2.3.0 之后,可以通过配置设置开启 Spring Boot 的优雅停机功能,如下所示:

# 开启优雅停机,默认值:immediate 为立即关闭
server.shutdown=graceful
# 设置缓冲期,最大等待时间,默认:30秒
spring.lifecycle.timeout-per-shutdown-phase=60s

此时,应用在关闭时,Web 服务器将不再接受新请求,并等待正在进行的请求完成的缓冲时间。

然而,如果是 Spring Boot 2.3.0 之前,就需要自行扩展(线程池)来实现优雅停机了。它的核心实现实现是在系统关闭时会调用 ShutdownHook,然后在 ShutdownHook 中阻塞 Web 容器的线程池,直到所有请求都处理完毕再关闭程序,这样就实现自定义优雅线下了。

但是,不同的 Web 容器(Tomcat、Jetty、Undertow)有不同的自定义优雅停机的方法,以 Tomcat 为例,它的自定义优雅停机实现如下。

法二:配置Tomcat 容器优雅停机

设置Tomcat 容器关闭代码

实现 TomcatConnectorCustomizer 接口,用于在应用关闭时暂停 Tomcat 连接器:

public class TomcatGracefulShutdown implements TomcatConnectorCustomizer, ApplicationListener<ContextClosedEvent> {
    private volatile Connector connector;
    public void customize(Connector connector) {
        this.connector = connector;
    }
    public void onApplicationEvent(ContextClosedEvent contextClosedEvent) {
        this.connector.pause();
        Executor executor = this.connector.getProtocolHandler().getExecutor();
        if (executor instanceof ThreadPoolExecutor) {
            try {
                log.info("Start to shutdown tomcat thread pool");
                ThreadPoolExecutor threadPoolExecutor = (ThreadPoolExecutor) executor;
                threadPoolExecutor.shutdown();
                if (!threadPoolExecutor.awaitTermination(20, TimeUnit.SECONDS)) {
                    log.warn("Tomcat thread pool did not shutdown gracefully within 20 seconds. ");
                }
            } catch (InterruptedException e) {
                log.warn("Fail to shut down tomcat thread pool ", e);
            }
        }
    }
}

设置 Tomcat 自动装配

在配置类中声明该 Bean 并将其注册为 Tomcat 的 ConnectorCustomizer:

@Configuration
@ConditionalOnClass({Servlet.class, Tomcat.class})
public static class TomcatConfiguration {
    @Bean
    public TomcatGracefulShutdown tomcatGracefulShutdown() {
        return new TomcatGracefulShutdown();
    }
    @Bean
    public EmbeddedServletContainerFactory tomcatEmbeddedServletContainerFactory(TomcatGracefulShutdown gracefulShutdown) {
        TomcatEmbeddedServletContainerFactory tomcatFactory = new TomcatEmbeddedServletContainerFactory();
        tomcatFactory.addConnectorCustomizers(gracefulShutdown);
        return tomcatFactory;
    }
}

总结

实现应用程序的优雅退出对于确保服务的可靠性和数据一致性至关重要。Spring Boot 从 2.3.0 版本开始提供了开箱即用的优雅退出支持,低于该版本则需要手动扩展实现。无论使用哪种方式,都应该遵循上述最佳实践,以确保应用程序能够安全、高效地关闭。同时,对于不同的 Web 容器,优雅退出的具体实现细节也会有所差异,需要合理配置。

到此这篇关于Spring Boot 实现程序的优雅退出的文章就介绍到这了,更多相关Spring Boot程序退出内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

相关文章

  • SpringBoot整合XxlJob分布式任务调度平台

    SpringBoot整合XxlJob分布式任务调度平台

    xxl-job是一个开源的分布式定时任务框架,它可以与其他微服务组件一起构成微服务集群。它的调度中心(xxl-job)和执行器(自己的springboot项目中有@XxlJob("定时任务名称")的方法)是相互分离,分开部署的,两者通过HTTP协议进行通信
    2023-02-02
  • JVM(Java虚拟机)简介(动力节点Java学院整理)

    JVM(Java虚拟机)简介(动力节点Java学院整理)

    Java虚拟机(Jvm)是可运行Java代码的假想计算机。Java虚拟机包括一套字节码指令集、一组寄存器、一个栈、一个垃圾回收堆和一个存储方法域。对java jvm 虚拟机感兴趣的朋友通过本文一起学习吧
    2017-04-04
  • Java下载https文件并上传阿里云oss服务器

    Java下载https文件并上传阿里云oss服务器

    这篇文章主要介绍了Java下载https文件并上传到阿里云oss服务器,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下
    2020-01-01
  • SpringMVC form标签引入及使用方法

    SpringMVC form标签引入及使用方法

    这篇文章主要介绍了SpringMVC form标签引入及使用方法,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下
    2020-06-06
  • Java字符串工具类从原生到第三方库的高效实践详解

    Java字符串工具类从原生到第三方库的高效实践详解

    字符串是我们在编程中最常使用的一种数据类型,Java中用类来描述字符串,其中最常用的字符串处理类是String,这篇文章主要介绍了Java字符串工具类从原生到第三方库的高效实践的相关资料,需要的朋友可以参考下
    2025-08-08
  • 一文带你搞懂什么是BIO

    一文带你搞懂什么是BIO

    BIO英文全名是 blocking IO,也叫做 阻塞IO,是最容易理解、最容易实现的IO工作方式,本文就来通过一些简单的示例为大家讲讲什么是BIO吧
    2023-06-06
  • java Volatile与Synchronized的区别

    java Volatile与Synchronized的区别

    这篇文章主要介绍了java Volatile与Synchronized的区别,帮助大家更好的理解和使用Java,感兴趣的朋友可以了解下
    2020-12-12
  • 深入了解与实例应用pinyin4j库

    深入了解与实例应用pinyin4j库

    在Java开发中,pinyin4j库是处理汉字与拼音转换的重要工具,提供将汉字转换为全拼音和提取汉字首字母的核心功能,本文详细探讨了pinyin4j库的使用方法、核心功能和实例应用,感兴趣的朋友跟随小编一起看看吧
    2025-08-08
  • SpringBoot日程管理Quartz与定时任务Task实现详解

    SpringBoot日程管理Quartz与定时任务Task实现详解

    定时任务是企业级开发中必不可少的组成部分,诸如长周期业务数据的计算,例如年度报表,诸如系统脏数据的处理,再比如系统性能监控报告,还有抢购类活动的商品上架,这些都离不开定时任务。本节将介绍两种不同的定时任务技术
    2022-09-09
  • Java中的浮点数分析

    Java中的浮点数分析

    Java中的浮点数分析...
    2006-12-12

最新评论