当前位置: 首页 > news >正文

spring boot项目优雅停机

1、关闭流程

  1. 停止接收请求和内部线程。
  2. 判断是否有线程正在执行。
  3. 等待正在执行的线程执行完毕。
  4. 停止容器。

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项目时&#xff0c;如果有访问请求过来&#xff0c;请求会被拒绝并返回错误提示。 在kill Spring Boot项目时&#xff0c;Sp…...

链式存储方式下字符串的replace(S,T1,T2)运算

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

unity脚本_Mathf和Math c#

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

轻量级仿 Spring Boot=嵌入式 Tomcat+Spring MVC

啥&#xff1f;Spring Boot 不用&#xff1f;——对。就只是使用 Spring MVC Embedded Tomcat&#xff0c;而不用 Boot。为啥&#xff1f;——因为 Boot 太重了&#xff1a;&#xff09; 那是反智吗&#xff1f;Spring Boot 好好的就只是因为太重就不用&#xff1f;——稍安勿…...

笔记Kubernetes核心技术-之Controller

2、Controller 2.1、概述 在集群上管理和运行容器的对象&#xff0c;控制器(也称为&#xff1a;工作负载)&#xff0c;Controller实际存在的&#xff0c;Pod是抽象的&#xff1b; 2.2、Pod和Controller关系 Pod是通过Controller实现应用运维&#xff0c;比如&#xff1a;弹…...

Azure云工作站上做Machine Learning模型开发 - 全流程演示

目录 本文内容先决条件从“笔记本”开始设置用于原型制作的新环境&#xff08;可选&#xff09;创建笔记本开发训练脚本迭代检查结果 关注TechLead&#xff0c;分享AI全维度知识。作者拥有10年互联网服务架构、AI产品研发经验、团队管理经验&#xff0c;同济本复旦硕&#xff0…...

前端 : 用html ,css,js写一个你画我猜的游戏

1.HTML&#xff1a; <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是一款功能强大的矢量图形编辑软件&#xff0c;由Adobe公司开发。它是设计师、艺术家和创意专业人士的首选工具&#xff0c;用于创建和编辑各种矢量图形、插图、图标、标志和艺术作品。 以下是Adobe Illustrator的主要功能和特点&#xff1a; 矢量图形编辑&…...

【Git企业开发】第二节.Git 的分支管理

作者简介&#xff1a;大家好&#xff0c;我是未央&#xff1b; 博客首页&#xff1a;未央.303 系列专栏&#xff1a;Git企业级开发 每日一句&#xff1a;人的一生&#xff0c;可以有所作为的时机只有一次&#xff0c;那就是现在&#xff01;&#xff01;&#xff01;&#xff0…...

第三章认识Node.js模块化开发

目录 认识Node.js 概述 作用 基本使用 Node.js的运行 Node.js的组成 Node.js的语法 Node.js全局对象 认识模块化开发 概述 场景 特点 模块成员的导入和导出 Node.js 模块化语法 导入模块 导出模块 ES6 模块化语法 导入模块 导出模块 项目 认识Node.js 概述…...

扩展Nginx的无限可能:掌握常见扩展模块和第三方插件的使用方法

Nginx是一款高性能的开源Web服务器和反向代理服务器。它具有模块化的架构&#xff0c;可以通过扩展模块和插件来增强其功能。在本文中&#xff0c;我将围绕Nginx的扩展模块和插件进行讲解&#xff0c;并提供一些常见的扩展模块和第三方插件的示例。 一、Nginx扩展模块 Nginx的…...

centos遇到的问题

lsof -i :8091 > 查看这个端口的线程 lsof &#xff1a; list open files 列出打开文件 -i &#xff1a; internet linux检测系统进程和服务&#xff1a; top &#xff1a; 实时监视系统的进程和资源的利用情况htop &#xff1a; top的增强版 问题&#xff1a; -bash: …...

本机spark 通idea连接Oracle的坑

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

网络协议--DNS:域名系统

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

计算机视觉注意力机制小盘一波 (学习笔记)

将注意力的阶段大改分成了4个阶段 1.将深度神经网络与注意力机制相结合&#xff0c;代表性方法为RAM ⒉.明确预测判别性输入特征&#xff0c;代表性方法为STN 3.隐性且自适应地预测潜在的关键特征&#xff0c;代表方法为SENet 4.自注意力机制 通道注意力 在深度神经网络中…...

LVS+keepalive高可用集群

keepalive简介 keepalive为LVS应用延伸的高可用服务。lvs的调度器无法做高可用。但keepalive不是为lvs专门集群服务的&#xff0c;也可以为其他的的代理服务器做高可用。 keepalive在lvs的高可用集群&#xff0c;主调度器和备调度器(可以有多个) 一主两备或一主一备。 VRRP: k…...

Thread 和 Runnable 的区别

Thread 和 Runnable 接口的区别有四个&#xff1a; Thread 是一个类&#xff0c;Runnable 是接口&#xff0c;因为在 Java 语言里面的继承特性&#xff0c;接口可以支持多继承&#xff0c;而类只能单一继承。所以如果在已经存在继承关系的类里面要实现线程的话&#xff0c;只能…...

图神经网络和分子表征:5. Completeness

大家都知道 “两点确定一线&#xff0c;三点确定一平面”&#xff0c;那么多少个变量可以确定一个分子呢&#xff1f;这是最近顶刊们热烈讨论的话题。 &#xff08;据笔者不完全统计&#xff09;最早在 SphereNet &#xff08;2022 ICLR&#xff09;论文里&#xff0c;摘要上就…...

css-渐变色矩形

效果图&#xff1a; 代码&#xff1a; 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项目地址&#xff1a;https://gitee.com/lemur/easypoi easypoi的Maven依赖&#xff1a; <dependency><groupId>cn.afterturn</groupId><artifactId>easypoi-spring-boot-starter<…...

DevExpress 2020.1中文汉化保姆级教程:从注册到配置全流程详解

DevExpress 2020.1中文汉化全流程实战指南&#xff1a;从零开始打造本地化开发环境 在软件开发领域&#xff0c;DevExpress作为一套功能强大的.NET控件库&#xff0c;因其丰富的UI组件和高效的数据可视化能力而广受开发者青睐。然而对于非英语母语的开发者而言&#xff0c;面对…...

一、RuoYi-Vue3项目模块化架构与二次开发实战

1. RuoYi-Vue3模块化架构深度解析 第一次接触RuoYi-Vue3时&#xff0c;最让我惊艳的就是它清晰的模块化设计。这个基于Spring BootVue3的前后端分离框架&#xff0c;通过六大核心模块的巧妙组合&#xff0c;既保证了功能完整性&#xff0c;又为二次开发留足了空间。就像搭积木一…...

Ostrakon-VL-8B在VMware虚拟机中的一站式部署与性能调优

Ostrakon-VL-8B在VMware虚拟机中的一站式部署与性能调优 想在本地隔离环境里跑通一个强大的多模态大模型&#xff0c;比如Ostrakon-VL-8B&#xff0c;但又不想折腾物理机或者担心影响主系统&#xff1f;VMware虚拟机是个不错的选择。不过&#xff0c;在虚拟机里部署AI应用&…...

Phi-4-mini-reasoning vLLM服务加固:限流熔断、输入清洗、输出长度约束配置

Phi-4-mini-reasoning vLLM服务加固&#xff1a;限流熔断、输入清洗、输出长度约束配置 1. 模型服务概述 Phi-4-mini-reasoning 是一个基于合成数据构建的轻量级开源模型&#xff0c;专注于高质量、密集推理的数据&#xff0c;并进一步微调以提高更高级的数学推理能力。该模型…...

别再浪费手机性能了!Blackmagic Camera 搭配 LUT 滤镜包,解锁夜景和人物拍摄的隐藏技巧

Blackmagic Camera 与 LUT 滤镜包&#xff1a;解锁手机摄影的隐藏潜力 手机摄影早已不再是简单的记录工具&#xff0c;而是可以创作出专业级影像的利器。对于追求画质的摄影爱好者和小型工作室来说&#xff0c;Blackmagic Camera 这款专业级拍摄应用配合精心调校的 LUT 滤镜包&…...

28 openclaw负载均衡实现:应对高并发场景的解决方案

背景/痛点在OpenClaw项目中&#xff0c;随着业务规模的扩大&#xff0c;单节点处理能力逐渐成为瓶颈。特别是在高并发场景下&#xff0c;如秒杀活动、实时数据推送等&#xff0c;如何合理分配负载、避免单点故障、提升整体吞吐量&#xff0c;成为架构设计的核心挑战。传统的负载…...

Windows任务栏美化完全指南:打造个性化桌面体验

Windows任务栏美化完全指南&#xff1a;打造个性化桌面体验 【免费下载链接】TranslucentTB A lightweight utility that makes the Windows taskbar translucent/transparent. 项目地址: https://gitcode.com/gh_mirrors/tr/TranslucentTB Windows任务栏美化是许多用户…...

雪花算法:分布式世界的“身份证号”

嘿&#xff0c;朋友&#xff01;想象一下&#xff0c;你是一家拥有几千台服务器的互联网大厂架构师。现在有个小麻烦&#xff1a;你的订单系统每秒钟要生成几万个订单号。如果让数据库自己搞&#xff08;自增ID&#xff09;&#xff0c;几台数据库凑在一起&#xff0c;肯定会出…...

BiliBiliCCSubtitle:3分钟掌握B站字幕下载与格式转换的终极指南

BiliBiliCCSubtitle&#xff1a;3分钟掌握B站字幕下载与格式转换的终极指南 【免费下载链接】BiliBiliCCSubtitle 一个用于下载B站(哔哩哔哩)CC字幕及转换的工具; 项目地址: https://gitcode.com/gh_mirrors/bi/BiliBiliCCSubtitle 你是否经常需要从B站视频中提取字幕内…...

当SPC焕发新生:云质信息重构制造质量管理新范式

传统SPC&#xff1a;那些让人头疼的“老毛病”说实话&#xff0c;很多企业斥巨资引入的SPC软件&#xff0c;实际使用体验与高级版Excel相差无几。数据需手动导入&#xff0c;图表需逐一点选生成&#xff0c;想要进行跨维度分析&#xff0c;更是要先将数据导出&#xff0c;借助其…...