-
spring boot不同版本的优雅关闭(graceful shutdown)和在windows下winsw服务方式运行的配置
起因#
- spring boot默认是不会优雅关闭的,这样就导致在重启时会将正在运行的程序打断,导致故障发生。
当前解决方式#
-
引入
spring-boot-starter-actuator
监控类库,它其中一个功能支持优雅关闭。 - spring boot 2.3版本开始,自己集成了优雅关闭,无需再引入上方类库即可实现优雅关闭。
坑爹的地方#
-
spring-boot-starter-actuator
文档中说是支持优雅关闭,但仅仅是spring层面上的,不和tomcat等容器挂钩,直到spring boot 2.3开启自带的优雅关闭后才真正能实现,也就是说2.3之前的版本根本实现不了优雅关闭,需要自己来进一步按照使用的容器做处理才行,参考这个issue:Allow the embedded web server to be shut down gracefully。 -
2.3以上版本,如果是在linux下,发送命令
kill -2 xxx
可以触发优雅关闭,但是在windows下,只有ctrl+c
才能触发(可以在idea下用run里面的exit
按钮模拟),但windows下我们一般是用服务来运行,所以永远无法触发ctrl+c
,因此即便是2.3版本后,windows下也必须安装spring-boot-starter-actuator
来通过发送http请求来实现优雅关闭。
2.3以上版本的处理方法(如果是用tomcat容器需要9.0.33以上)#
-
在
application.yml
中增加:# 开启优雅关闭 server: shutdown: graceful # 配置强制结束时间,不配置的话默认30s spring: lifecycle: timeout-per-shutdown-phase: 30s
-
配置好后就支持优雅关闭了,linux端只需要在
systemctl
的配置文件中设置关闭命令是kill -2 xxxPID
,pid可以通过文件或命令根据端口查找什么的,手头上暂没有linux来测试,后期有了后补上完整脚本。 - widows端虽然也支持,但是如果用服务方式运行是没法触发ctrl+c相同的效果的,所以还是不行。
2.3以下的处理方法(或者是2.3版本以上的windows端)#
-
引入
spring-boot-starter-actuator
的maven类库<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-actuator</artifactId> </dependency>
-
在
application.yml
中增加:#监控相关配置 management: endpoint: # 开启 shutdown: enabled: true endpoints: web: # 只允许shutdown,为了安全,其它想要监控自行配置 exposure: include: "shutdown" # 自定义请求路径,为了安全 base-path: /xxx server: #自定义请求端口,为了安全 port: 7080
curl -X POST http://localhost:自定义端口/自定义路径/shutdown
,由于路径和端口都是自定义的,所以安全性方面不用太过担心。 -
分支1:如果是2.3版本以上的windows端,再开启自带的优雅关闭,就可以通过http请求来实现了
# 开启优雅关闭 server: shutdown: graceful # 配置强制结束时间,不配置的话默认30s spring: lifecycle: timeout-per-shutdown-phase: 30s
-
分支2:如果是2.3以下版本,此时虽然可以发送http请求来关闭,但实际上不会等待正在执行的程序,而是会直接关闭,还应该配置容器相关,以tomcat容器为例:
-
创建相关类:
package xxx.xxx.xxx; import lombok.extern.slf4j.Slf4j; import org.apache.catalina.connector.Connector; import org.springframework.boot.web.embedded.tomcat.TomcatConnectorCustomizer; import org.springframework.context.ApplicationListener; import org.springframework.context.event.ContextClosedEvent; import java.util.concurrent.Executor; import java.util.concurrent.ThreadPoolExecutor; import java.util.concurrent.TimeUnit; /** * 优雅关闭 */ @Slf4j public class GracefulShutdown implements TomcatConnectorCustomizer, ApplicationListener<ContextClosedEvent> { private volatile Connector connector; /** * 30s强制关闭 */ private static final int TIMEOUT = 30; /** * 自定义链接 * * @param connector */ @Override public void customize(Connector connector) { this.connector = connector; } /** * 关闭时触发 * * @param event */ @Override public void onApplicationEvent(ContextClosedEvent event) { this.connector.pause(); Executor executor = this.connector.getProtocolHandler().getExecutor(); if (executor instanceof ThreadPoolExecutor) { try { ThreadPoolExecutor threadPoolExecutor = (ThreadPoolExecutor) executor; threadPoolExecutor.shutdown(); if (!threadPoolExecutor.awaitTermination(TIMEOUT, TimeUnit.SECONDS)) { log.warn("Tomcat thread pool did not shut down gracefully within " + "30 seconds. Proceeding with forceful shutdown"); } } catch (InterruptedException ex) { Thread.currentThread().interrupt(); } } } }
- 在启动类中引入:
package xx.xxx.xxx; import org.springframework.beans.factory.annotation.Qualifier; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.boot.web.embedded.tomcat.TomcatServletWebServerFactory; import org.springframework.boot.web.servlet.server.ConfigurableServletWebServerFactory; import org.springframework.context.annotation.Bean; @SpringBootApplication public class XxxxApplication { /** * 优雅关闭bean * @return */ @Bean("gracefulShutdown") public GracefulShutdown gracefulShutdown() { return new GracefulShutdown(); } /** * tomcat配置优雅关闭 * @param gracefulShutdown * @return */ @Bean public ConfigurableServletWebServerFactory webServerFactory(@Qualifier("gracefulShutdown") GracefulShutdown gracefulShutdown) { TomcatServletWebServerFactory factory = new TomcatServletWebServerFactory(); factory.addConnectorCustomizers(gracefulShutdown); return factory; } public static void main(String[] args) { SpringApplication.run(XxxxApplication .class, args); } }
- 以上配置后再发送http请求才会优雅关闭,但仅适用于tomcat容器,undertow容器可以参考这个:Spring boot 2.0 之优雅停机
-
创建相关类:
windows端用winsw设置为服务运行时的配置#
- winsw可以从这里下载:winsw,主要作用就是可以让程序以服务的方式后台运行并能开机启动等
- 需要下载windows下的curl,地址:curl for Windows
-
配置winsw的config文件:
<service> <!-- ID of the service. It should be unique across the Windows system--> <id>XXX</id> <!-- Display name of the service --> <name>xxx</name> <!-- Service description --> <description>xxx名称(powered by WinSW)</description> <!-- Path to the executable, which should be started --> <env name="JAVA_HOME" value="%JAVA_HOME%"/> <executable>java</executable> <startarguments>-jar -Xms128m -Xmx512m "D:\jar包路径\xxx.jar"</startarguments> <!--停止 --> <stopexecutable>D:\curl路径\bin\curl.exe</stopexecutable> <stoparguments>-X POST http://localhost:7080/xxx/shutdown</stoparguments> <!--不配置的话默认15s--> <stoptimeout>30 sec</stoptimeout> <startmode>Automatic</startmode> <logmode>none</logmode> </service>
来源:https://www.cnblogs.com/vishun/p/15527810.html
最新更新
python爬虫及其可视化
使用python爬取豆瓣电影短评评论内容
nodejs爬虫
Python正则表达式完全指南
爬取豆瓣Top250图书数据
shp 地图文件批量添加字段
爬虫小试牛刀(爬取学校通知公告)
【python基础】函数-初识函数
【python基础】函数-返回值
HTTP请求:requests模块基础使用必知必会
SQL SERVER中递归
2个场景实例讲解GaussDB(DWS)基表统计信息估
常用的 SQL Server 关键字及其含义
动手分析SQL Server中的事务中使用的锁
openGauss内核分析:SQL by pass & 经典执行
一招教你如何高效批量导入与更新数据
天天写SQL,这些神奇的特性你知道吗?
openGauss内核分析:执行计划生成
[IM002]Navicat ODBC驱动器管理器 未发现数据
初入Sql Server 之 存储过程的简单使用
uniapp/H5 获取手机桌面壁纸 (静态壁纸)
[前端] DNS解析与优化
为什么在js中需要添加addEventListener()?
JS模块化系统
js通过Object.defineProperty() 定义和控制对象
这是目前我见过最好的跨域解决方案!
减少回流与重绘
减少回流与重绘
如何使用KrpanoToolJS在浏览器切图
performance.now() 与 Date.now() 对比