spring boot项目优雅停机
1、关闭流程
- 停止接收请求和内部线程。
- 判断是否有线程正在执行。
- 等待正在执行的线程执行完毕。
- 停止容器。
2、关闭过程有新的请求
在kill Spring Boot项目时,如果有访问请求过来,请求会被拒绝并返回错误提示。
在kill Spring Boot项目时,Spring Boot应用会先停止接收请求和内部线程,然后判断是否有线程正在执行,如果有正在执行的线程,就等待线程执行完毕,最后停止容器。因此,当有访问请求过来时,请求会被拒绝并返回错误提示。
3、预留缓冲时间
Spring Boot的优雅停机功能,可以在收到终止信号后,不再接受、处理新请求,需要在终止进程之前预留一小段缓冲时间,以完成正在处理的请求。不要直接使用kill -9杀死进程。
4、优雅停机方式
4.1 通过Actuator的Endpoint机制关闭服务
使用此方法,需要先添加spring-boot-starter-actuator
监控服务依赖包
<dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
默认配置下,shutdown
端点是关闭的,需要在application.properties
里配置里面开启:
management.endpoint.shutdown.enabled=true
management.endpoints.web.exposure.include=shutdown
执行关闭接口
curl -X POST http://localhost:8080/actuator/shutdown
4.2 使用ApplicationContext的close方法关闭服务
在应用启用的时候,获取ApplicationContext
对象,然后在相关的位置调用close
方法,就可以关闭服务。
ConfigurableApplicationContext ctx = SpringApplication.run(ShutdowndemoApplication.class, args);
try {TimeUnit.SECONDS.sleep(10);
} catch (InterruptedException e) {e.printStackTrace();
}
ctx.close();
我们也可以自己写一个Controller
,获取对应的ApplicationContext
对象,通过api
操作调用close
方法关停服务,示例代码如下:
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.DisposableBean;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.context.ApplicationEvent;
import org.springframework.context.ConfigurableApplicationContext;
import org.springframework.context.annotation.Lazy;
import org.springframework.stereotype.Service;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;import javax.servlet.http.HttpServletRequest;@Slf4j
@Service
@Lazy(false)
public class SpringContextHolder implements ApplicationContextAware, DisposableBean {private static ApplicationContext applicationContext = null;@Overridepublic void setApplicationContext(ApplicationContext applicationContext) {SpringContextHolder.applicationContext = applicationContext;}@Overridepublic void destroy() {SpringContextHolder.clearHolder();}/*** 关闭服务** @methodName: shutdownContext* @return: void* @author: weixiansheng* @date: 2023/10/25**/public static void shutdownContext() {((ConfigurableApplicationContext) applicationContext).close();}}
import com.ybw.util.SpringContextHolder;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;/*** @author weixiansheng* @version V1.0* @className ShutdownController* @date 2023/10/25**/
@RestController
public class ShutdownController {@GetMapping("/shutdown")public void shutdown(){SpringContextHolder.shutdownContext();}
}
4.3 监听服务pid,通过kill方式关闭服务(推荐)
通过api
方式来关停服务,在很多人看来并不安全,因为一旦接口泄漏了,意味着用户可以随便请求这个接口来关闭服务,其影响不言而喻,因此很多人建议在服务端,通过其他的方式来关闭服务,比如通过进程命令方式来关停。
在springboot
启动的时候将应用进程 ID 写入一个app.pid
文件,生成的路径可以指定,然后通过脚本命令方式来关闭服务。
@SpringBootApplication
public class SprintBootDemoApplication {public static void main(String[] args) {SpringApplication application = new SpringApplication(SprintBootDemoApplication.class);application.addListeners(new ApplicationPidFileWriter("D:\\app.pid"));application.run();}}
通过如下命令方式,可以安全的关闭服务。
cat /home/app/project1/app.pid | xargs kill
这种方式,也是目前在linux
操作系统中,使用较为普遍的一种解决方案,区别在于实现的方式可能不同,有的不用写文件,通过其他方式来获取应用进程 ID。
注意
如果使用
kill -9 <pid>
的方式关闭服务,服务的监听器不会收到任何消息,类似于直接强杀应用进程,此方法不可取!
4.4 使用SpringApplication的exit方法关闭服务
通过调用一个SpringApplication.exit()方法也可以退出程序,同时将生成一个退出码,这个退出码可以传递给所有的context。这个就是一个JVM的钩子,通过调用这个方法的话会把所有PreDestroy的方法执行并停止,并且传递给具体的退出码给所有Context。通过调用System.exit(exitCode)可以将这个错误码也传给JVM。程序执行完后最后会输出:Process finished with exit code 0,给JVM一个SIGNAL。
import org.springframework.boot.ExitCodeGenerator;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.context.ApplicationPidFileWriter;
import org.springframework.context.ConfigurableApplicationContext;@SpringBootApplication
public class SprintBootDemoApplication {public static void main(String[] args) {ConfigurableApplicationContext ctx = SpringApplication.run(SprintBootDemoApplication.class, args);exitApplication(ctx);}public static void exitApplication(ConfigurableApplicationContext context) {int exitCode = SpringApplication.exit(context, (ExitCodeGenerator) () -> 0);System.exit(exitCode);}
}
日志如下
[INFO ] 2023-10-25 15:49:05.640 [main] c.y.s.SprintBootDemoApplication - Starting SprintBootDemoApplication using Java 17.0.8 on LAPTOP-V56V2EJT with PID 44520 (D:\git-code\mygit\learn\spring\sprint-boot-demo\target\classes started by weixiansheng in D:\git-code\mygit\learn\spring\sprint-boot-demo)
[INFO ] 2023-10-25 15:49:05.643 [main] c.y.s.SprintBootDemoApplication - The following 1 profile is active: "dev"
[INFO ] 2023-10-25 15:49:06.638 [main] o.s.b.w.e.tomcat.TomcatWebServer - Tomcat initialized with port(s): 8080 (http)
[INFO ] 2023-10-25 15:49:06.647 [main] o.a.coyote.http11.Http11NioProtocol - Initializing ProtocolHandler ["http-nio-8080"]
[INFO ] 2023-10-25 15:49:06.648 [main] o.a.catalina.core.StandardService - Starting service [Tomcat]
[INFO ] 2023-10-25 15:49:06.649 [main] o.a.catalina.core.StandardEngine - Starting Servlet engine: [Apache Tomcat/9.0.60]
[INFO ] 2023-10-25 15:49:06.738 [main] o.a.c.c.C.[Tomcat].[localhost].[/] - Initializing Spring embedded WebApplicationContext
[INFO ] 2023-10-25 15:49:06.738 [main] o.s.b.w.s.c.ServletWebServerApplicationContext - Root WebApplicationContext: initialization completed in 1024 ms
[INFO ] 2023-10-25 15:49:07.007 [main] o.a.coyote.http11.Http11NioProtocol - Starting ProtocolHandler ["http-nio-8080"]
[INFO ] 2023-10-25 15:49:07.031 [main] o.s.b.w.e.tomcat.TomcatWebServer - Tomcat started on port(s): 8080 (http) with context path ''
[INFO ] 2023-10-25 15:49:07.039 [main] c.y.s.SprintBootDemoApplication - Started SprintBootDemoApplication in 1.969 seconds (JVM running for 3.815)
Disconnected from the target VM, address: '127.0.0.1:53475', transport: 'socket'Process finished with exit code 0
4.5 总结
在真实的工作中的时候4.3比较常用,程序中一般使用内存队列或线程池的时候最好要优雅的关机,将内存队列没有处理的保存起来或线程池中没处理完的程序处理完。但是因为停机的时候比较快,所以停服务的时候最好不要处理大量的数据操作,这样会影响程序停止。
以上这几种方法实现的话比较简单,但是真实工作中还需要考虑的点还很多,比如需要保护暴露的点不被别人利用,一般要加一些防火墙,或者只在内网使用,保证程序安全。
相关文章:
spring boot项目优雅停机
1、关闭流程 停止接收请求和内部线程。判断是否有线程正在执行。等待正在执行的线程执行完毕。停止容器。 2、关闭过程有新的请求 在kill Spring Boot项目时,如果有访问请求过来,请求会被拒绝并返回错误提示。 在kill Spring Boot项目时,Sp…...

链式存储方式下字符串的replace(S,T1,T2)运算
链式存储方式下字符串的replace运算 ⭐️题目⭐️思路⭐️代码✨定义结点✨打印字符串函数✨计算字符串函数✨初始化字符串函数✨代码解读✨字符串替换函数✨字符串替换函数解读✨ 主函数✨完整代码 实现在链式存储下字符串的replace(S,T1,T2),来自课本习题的一道题…...

unity脚本_Mathf和Math c#
首先创建一个脚本 当我们要做一个值趋近于一个值变化时 可以用Mathf.Lerp(start,end,time);方法实现 比如物体跟随...

轻量级仿 Spring Boot=嵌入式 Tomcat+Spring MVC
啥?Spring Boot 不用?——对。就只是使用 Spring MVC Embedded Tomcat,而不用 Boot。为啥?——因为 Boot 太重了:) 那是反智吗?Spring Boot 好好的就只是因为太重就不用?——稍安勿…...

笔记Kubernetes核心技术-之Controller
2、Controller 2.1、概述 在集群上管理和运行容器的对象,控制器(也称为:工作负载),Controller实际存在的,Pod是抽象的; 2.2、Pod和Controller关系 Pod是通过Controller实现应用运维,比如:弹…...

Azure云工作站上做Machine Learning模型开发 - 全流程演示
目录 本文内容先决条件从“笔记本”开始设置用于原型制作的新环境(可选)创建笔记本开发训练脚本迭代检查结果 关注TechLead,分享AI全维度知识。作者拥有10年互联网服务架构、AI产品研发经验、团队管理经验,同济本复旦硕࿰…...

前端 : 用html ,css,js写一个你画我猜的游戏
1.HTML: <body><div id "content"><div id "box1">计时器</div><div id"box"><div id "top"><div id "box-top-left">第几题:</div><div id "box…...

Illustrator 2024(AI v28.0)
Illustrator 2024是一款功能强大的矢量图形编辑软件,由Adobe公司开发。它是设计师、艺术家和创意专业人士的首选工具,用于创建和编辑各种矢量图形、插图、图标、标志和艺术作品。 以下是Adobe Illustrator的主要功能和特点: 矢量图形编辑&…...

【Git企业开发】第二节.Git 的分支管理
作者简介:大家好,我是未央; 博客首页:未央.303 系列专栏:Git企业级开发 每日一句:人的一生,可以有所作为的时机只有一次,那就是现在!!!࿰…...
第三章认识Node.js模块化开发
目录 认识Node.js 概述 作用 基本使用 Node.js的运行 Node.js的组成 Node.js的语法 Node.js全局对象 认识模块化开发 概述 场景 特点 模块成员的导入和导出 Node.js 模块化语法 导入模块 导出模块 ES6 模块化语法 导入模块 导出模块 项目 认识Node.js 概述…...
扩展Nginx的无限可能:掌握常见扩展模块和第三方插件的使用方法
Nginx是一款高性能的开源Web服务器和反向代理服务器。它具有模块化的架构,可以通过扩展模块和插件来增强其功能。在本文中,我将围绕Nginx的扩展模块和插件进行讲解,并提供一些常见的扩展模块和第三方插件的示例。 一、Nginx扩展模块 Nginx的…...
centos遇到的问题
lsof -i :8091 > 查看这个端口的线程 lsof : list open files 列出打开文件 -i : internet linux检测系统进程和服务: top : 实时监视系统的进程和资源的利用情况htop : top的增强版 问题: -bash: …...

本机spark 通idea连接Oracle的坑
1. 报错:Exception in thread "main" java.lang.NoSuchMethodError: scala.Product.$init$(Lscala/Product;)V 查询网上资料,是idea引入的scala运行环境版本与idea默认的scala版本不一样 也就是写的项目中的pom的spark版本与idea默认的版本不…...

网络协议--DNS:域名系统
14.1 引言 域名系统(DNS)是一种用于TCP/IP应用程序的分布式数据库,它提供主机名字和IP地址之间的转换及有关电子邮件的选路信息。这里提到的分布式是指在Internet上的单个站点不能拥有所有的信息。每个站点(如大学中的系、校园、…...

计算机视觉注意力机制小盘一波 (学习笔记)
将注意力的阶段大改分成了4个阶段 1.将深度神经网络与注意力机制相结合,代表性方法为RAM ⒉.明确预测判别性输入特征,代表性方法为STN 3.隐性且自适应地预测潜在的关键特征,代表方法为SENet 4.自注意力机制 通道注意力 在深度神经网络中…...

LVS+keepalive高可用集群
keepalive简介 keepalive为LVS应用延伸的高可用服务。lvs的调度器无法做高可用。但keepalive不是为lvs专门集群服务的,也可以为其他的的代理服务器做高可用。 keepalive在lvs的高可用集群,主调度器和备调度器(可以有多个) 一主两备或一主一备。 VRRP: k…...
Thread 和 Runnable 的区别
Thread 和 Runnable 接口的区别有四个: Thread 是一个类,Runnable 是接口,因为在 Java 语言里面的继承特性,接口可以支持多继承,而类只能单一继承。所以如果在已经存在继承关系的类里面要实现线程的话,只能…...

图神经网络和分子表征:5. Completeness
大家都知道 “两点确定一线,三点确定一平面”,那么多少个变量可以确定一个分子呢?这是最近顶刊们热烈讨论的话题。 (据笔者不完全统计)最早在 SphereNet (2022 ICLR)论文里,摘要上就…...

css-渐变色矩形
效果图: 代码: html: <!DOCTYPE html> <html><head><meta charset"utf-8"><meta name"viewport" content"initial-scale1.0, user-scalableno" /><title></title><link …...
使用easypoi-spring-boot-starter 4.1.1导入excel报错NoSuchMethodError和NoSuchMethodError
前言 使用easypoi进行excel的导入遇到的错误以及解决办法 easypoi项目地址:https://gitee.com/lemur/easypoi easypoi的Maven依赖: <dependency><groupId>cn.afterturn</groupId><artifactId>easypoi-spring-boot-starter<…...
HTML 语义化
目录 HTML 语义化HTML5 新特性HTML 语义化的好处语义化标签的使用场景最佳实践 HTML 语义化 HTML5 新特性 标准答案: 语义化标签: <header>:页头<nav>:导航<main>:主要内容<article>&#x…...

基于ASP.NET+ SQL Server实现(Web)医院信息管理系统
医院信息管理系统 1. 课程设计内容 在 visual studio 2017 平台上,开发一个“医院信息管理系统”Web 程序。 2. 课程设计目的 综合运用 c#.net 知识,在 vs 2017 平台上,进行 ASP.NET 应用程序和简易网站的开发;初步熟悉开发一…...
在HarmonyOS ArkTS ArkUI-X 5.0及以上版本中,手势开发全攻略:
在 HarmonyOS 应用开发中,手势交互是连接用户与设备的核心纽带。ArkTS 框架提供了丰富的手势处理能力,既支持点击、长按、拖拽等基础单一手势的精细控制,也能通过多种绑定策略解决父子组件的手势竞争问题。本文将结合官方开发文档,…...

【2025年】解决Burpsuite抓不到https包的问题
环境:windows11 burpsuite:2025.5 在抓取https网站时,burpsuite抓取不到https数据包,只显示: 解决该问题只需如下三个步骤: 1、浏览器中访问 http://burp 2、下载 CA certificate 证书 3、在设置--隐私与安全--…...

c#开发AI模型对话
AI模型 前面已经介绍了一般AI模型本地部署,直接调用现成的模型数据。这里主要讲述讲接口集成到我们自己的程序中使用方式。 微软提供了ML.NET来开发和使用AI模型,但是目前国内可能使用不多,至少实践例子很少看见。开发训练模型就不介绍了&am…...

学校时钟系统,标准考场时钟系统,AI亮相2025高考,赛思时钟系统为教育公平筑起“精准防线”
2025年#高考 将在近日拉开帷幕,#AI 监考一度冲上热搜。当AI深度融入高考,#时间同步 不再是辅助功能,而是决定AI监考系统成败的“生命线”。 AI亮相2025高考,40种异常行为0.5秒精准识别 2025年高考即将拉开帷幕,江西、…...
Angular微前端架构:Module Federation + ngx-build-plus (Webpack)
以下是一个完整的 Angular 微前端示例,其中使用的是 Module Federation 和 npx-build-plus 实现了主应用(Shell)与子应用(Remote)的集成。 🛠️ 项目结构 angular-mf/ ├── shell-app/ # 主应用&…...
【Java学习笔记】BigInteger 和 BigDecimal 类
BigInteger 和 BigDecimal 类 二者共有的常见方法 方法功能add加subtract减multiply乘divide除 注意点:传参类型必须是类对象 一、BigInteger 1. 作用:适合保存比较大的整型数 2. 使用说明 创建BigInteger对象 传入字符串 3. 代码示例 import j…...

Docker 本地安装 mysql 数据库
Docker: Accelerated Container Application Development 下载对应操作系统版本的 docker ;并安装。 基础操作不再赘述。 打开 macOS 终端,开始 docker 安装mysql之旅 第一步 docker search mysql 》〉docker search mysql NAME DE…...

【Linux】Linux 系统默认的目录及作用说明
博主介绍:✌全网粉丝23W,CSDN博客专家、Java领域优质创作者,掘金/华为云/阿里云/InfoQ等平台优质作者、专注于Java技术领域✌ 技术范围:SpringBoot、SpringCloud、Vue、SSM、HTML、Nodejs、Python、MySQL、PostgreSQL、大数据、物…...