大数跨境
0
0

面试官:说说你们SpringBoot项目是如何优雅停机的?

面试官:说说你们SpringBoot项目是如何优雅停机的? Spring全家桶实战案例
2025-06-14
1
导读:面试官:说说你们SpringBoot项目是如何优雅停机的?

Spring Boot 3实战案例锦集PDF电子书已更新至100篇!

🎉🎉《Spring Boot实战案例合集》目前已更新133个案例,我们将持续不断的更新。文末有电子书目录。

💪💪永久更新承诺

我们郑重承诺,所有订阅合集的粉丝都将享受永久免费的后续更新服务

💌💌如何获取
订阅我们的合集点我订阅,并通过私信联系我们,我们将第一时间将电子书发送给您。

→ 现在就订阅合集

环境:SpringBoot3.4.2



1. 为什么要优雅停机

  1. 数据完整性:在停机过程中,如果暴力终止进程,可能会导致事务执行中断或业务处理不完整,从而在数据库或系统中留下脏数据或残留文件。优雅停机能够确保在停机前完成所有正在处理的请求,并保存相关数据,保证数据的完整性和一致性。

  2. 用户体验:优雅停机能够在终止服务前,不再接受新的请求,但会完成已接收的请求,从而避免用户请求被中断或超时,提升用户体验。

  3. 资源释放:优雅停机能够确保在停机过程中,系统资源得到正确的释放,避免资源泄露或浪费。


2. 准备测试环境

准测试的环境,模拟耗时操作及资源销毁动作。

2.1 环境准备

@Componentpublic class PersonService {
  @PreDestroy  public void destroy() {    try {      TimeUnit.SECONDS.sleep(5) ;    } catch (InterruptedException e) {      e.printStackTrace();    }    System.out.println("资源释放完成...") ;  }}

该Bean定义了销毁方法,容器在关闭时会执行。

@GetMapping("/index")public Object index() {  try {    System.out.println("执行任务...") ;    TimeUnit.SECONDS.sleep(30) ;    System.out.println("任务执行完成...") ;  } catch (InterruptedException e) {    e.printStackTrace();  }  return "demo index" ;}

该接口模拟耗时任务。主要用来观察发出停机信号后该接口是否会执行完成后再停机。

2.2 暴露停机

我们先来观察下暴露停机会是什么情况。

启动服务

请求/index接口

[root@pack ~]# curl http://localhost:8080/demos/index

强制终止进程

通过kill -9 强制终止进程

[root@pack ~]# jps31713 Jps26037 jar[root@pack ~]# kill -9 26037[root@pack ~]#

此时查看服务输出情况

请求的/index接口并没有执行完成,并且PersonService的销毁方法并没有执行。

3. 优雅停机方式

3.1 方式1

通过linux命令kill,但是这里我们不要添加-9 这样的参数。而是不是使用参数或者使用-15参数,示例如下:

[root@pack ~]# kill xxx  或者  kill -15 xxx

这里测试还是按照上面的方式进行,我们只需要观察服务控制台输出结果即可。

执行任务...java.lang.InterruptedException: sleep interrupted        at java.lang.Thread.sleep(Native Method)资源释放完成...

当通过上面的方式终止进程后,PersonService的销毁方法执行完成以后程序才终止。确保资源的释放。为什么SpringBoot程序能正确的关闭呢?这是因为SpringBoot程序默认为JVM注册了一个关闭钩子,也就是添加了下面这样的代码

Runtime.getRuntime().addShutdownHook(...)

有兴趣可以查看下SpringApplication源码。

当我们配置了如下参数后,SpringBoot程序就算你使用kill xxx或者kill -15 xxx也会立即终止。

spring:  main:    register-shutdown-hook: false

关闭注册钩子。

提示:你也可以直接通过Ctrl + C的方式来终止效果与kill - 15 是一样的。

3.2 方式2

通过如下配置,开启优雅关闭

server:  shutdown: graceful---spring:  main:    register-shutdown-hook: true

再次通过上面的方式进行测试,服务输出结果

当发出kill xxx信号后,我们请求的/index接口并没有直接终止,程序也没有立即终止而是等到所有的请求都结束以后才终止。这种优雅停机方式要比上一种优雅的太多了。

该种停机方式首先停止接收新的请求,然后等待所有正在执行的请求完成,最后关闭应用。

3.3 方式3

通过Actuator,Actuator提供了/shutdown接口,我们可以调用该接口进行程序的关闭。

引入依赖

<dependency>  <groupId>org.springframework.boot</groupId>  <artifactId>spring-boot-starter-actuator</artifactId></dependency>

默认情况下并没有开启shutdown接口,需要进行如下的配置

management:  endpoints:    web:      base-path: /ac    exposure:      include: '*'  endpoint:    shutdown:      enabled: true

接下来测试方式与上面相同,只不过停止服务需要通过如下接口

http://localhost:8080/ac/shutdown

当执行上面接口后

服务输出结果

服务与上面一样优雅的停机等待当前正处理的请求结束后再停机。

注意:使用了该种方式一定要做好安全防护,不要随意让人都可以去调用该接口。

推荐文章

六种策略,设计一个线程安全的 Java 类

太强了!Spring Boot 五大内置 "神兵" 工具

高级开发!扩展@Async功能,动态管理异步任务

打破限制!基于 AspectJ 的 Spring AOP 增强:final/static/private 方法全支持

非常实用!玩转 Spring Boot 接口参数类型转换,支持任意场景

请不要自己写!Spring Boot非常实用的内置功能

基于SpringBoot支持任意文件在线预览

SpringBoot请求参数还可以这样玩?很少有人知道

SpringBoot强大的分布式锁组件Lock4j,支持多种实现


以上是本篇文章的全部内容,如对你有帮助就请作者吃个棒棒糖🍭。

完毕!!!

【声明】内容源于网络
0
0
Spring全家桶实战案例
Java全栈开发,前端Vue2/3全家桶;Spring, SpringBoot 2/3, Spring Cloud各种实战案例及源码解读
内容 832
粉丝 0
Spring全家桶实战案例 Java全栈开发,前端Vue2/3全家桶;Spring, SpringBoot 2/3, Spring Cloud各种实战案例及源码解读
总阅读381
粉丝0
内容832