前言

Spring Boot 项目优雅关闭常用两种方案,一种是使用kill -2 和 -15 发送程序终止信号,另一种是使用spring-boot-actuator包提供一个优雅下线接口,这两种方案根据自己喜好来,万不得已别用kill -9就行,个人推荐第一种,对于Spring Boot 项目来说两种方法只是入口不同,最终关闭逻辑都是一样的,具体的逻辑会在接下来阐述。

一、Spring Boot 项目优雅关闭核心逻辑

只要是Spring项目无论是何种方法最终都是调用到Spring的AbstractApplicationContext.doClose() 方法来实现优雅关闭,这里介绍的两种方法只是入口不同而已,在后面方案中会详细介绍。

PS:Spring Boot版本 ≥ 2.0
不同版本可能实现不同不过最终都是调用到AbstractApplicationContext.doClose() 方法来实现的关闭。

二、方案原理和实现(这里不包含Tomcat优雅关闭在下面扩展中会有详细介绍)

方案一原理和实现示例(通过kill -2 和 -15 优雅关闭,这种方式SpringBoot是默认支持的)

kill -2 和 -15 是操作系统给该进程发送一个信号通知,告知应用主动关闭,应用可以监听并接收到信号,可以完成一些关闭回收等动作,然后自我停止,这些关闭信号并不是由spring感知,而是由java线程Signal Dispatcher监听,此线程将收到的信号交给JVM,JVM判断信号种类,如果是-2/-15等关闭类型,则交由java.lang.Shutdown完成关闭,关闭前会触发所有的shutdown hookRuntime.getRuntime().addShutdownHook() 可以添加自定义的 shutdown hook

在启动类SpringApplication中会调用自己的refreshContext方法,通过 SpringApplicationShutdownHook.addRuntimeShutdownHook() 方法调用 Runtime.getRuntime().addShutdownHook() 添加自定义的 shutdown hook,在进程接收到kill -2 或 -15 时触发。

在这里插入图片描述
SpringApplicationShutdownHook实现了 Runnable 重写了run 方法,当进程接收到kill -2 或 -15 时触发执行关闭逻辑。
在这里插入图片描述

演示

# 发送一个关闭信号通知
kill -15 pid

在这里插入图片描述
这里可以看到数据源定时任务等工具的关闭日志,还会看到一个线程池的关闭日志,这个后面扩展中会详细说明。

方案二原理和实现示例(通过spring-boot-actuator提供优雅关闭接口)

spring-boot-actuator是一个应用监控框架同时也提供了SpringBoot优雅下线的接口,原理还是一样的最终会调用到AbstractApplicationContext.doClose() 方法来实现的关闭,也可以自己写一个接口去调用AbstractApplicationContext.doClose(),这个有兴趣可以自己实现。

代码实现

  • POM
        <!--    监控 版本同步spring-boot    -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-actuator</artifactId>
        </dependency>
  • 配置文件
spring:
  lifecycle:
    # 优雅下线超时时间
    timeout-per-shutdown-phase: 1m
# 暴露 shutdown 接口
# 调用 curl -X POST http://127.0.0.1:18080/actuator/shutdown
management:
  server:
    ### 端口
    port: 18080
    ### 允许服务地址
    address: 127.0.0.1
  endpoint:
    ### 是否开启下线 默认关闭
    shutdown:
      enabled: true
  endpoints:
    web:
      exposure:
        ### 暴露接口
        include: shutdown

演示

在这里插入图片描述
这里看到的效果和方案一是一样的,可以看到数据源定时任务等工具的关闭日志,只是执行线程变了,线程池关闭看扩展。

三、扩展

通过 @PreDestroy 注解关闭自定义线程池和其它自定义工具

@PreDestroy是Java规范JSR-250引入的注解,定义了对象的销毁工作,同一期规范中还有注解@Resource,Spring也支持了这些注解,会在Spring提供的一个后置处理器InitDestroyAnnotationBeanPostProcessor中调用的,当Spring容器销毁时会调用到@PreDestroy标记的方法,在这个方法中自行处理关闭逻辑即可。

在这里插入图片描述

优雅关闭内嵌Tomcat

内嵌Tomcat会使用到TomcatWebServerTomcatWebServer提供了一个优雅关闭Tomcat的方法shutDownGracefully,如果不配置默认是直接关闭,需要在配置文件中配置server.shutdown = graceful 开启优雅关闭。
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

转自:
https://blog.csdn.net/weixin_44606481/article/details/132218666