Spring Boot 在关闭时,如果有请求没有响应完,在不同的容器会出现不同的结果,例如,在 Tomcat 和 Undertow 中会出现中断异常,那么就有可能对业务造成影响。所以,优雅停机非常有必要性,目前官方是没有提供很好的策略来实现。

Each SpringApplication registers a shutdown hook with the JVM to ensure that the ApplicationContext closes gracefully on exit. All the standard Spring lifecycle callbacks (such as the DisposableBean interface or the @PreDestroy annotation) can be used.

Spring Boot Application 在接收到停机信号后,可以通过 DisposableBean 接口 、 @PreDestroy 注解 或者 ContextClosedEvent 事件来处理优雅停机的相关逻辑。

版本信息

Spring Boot 版本: 2.0.0.RELEASE

Tomcat 优雅停机

@SpringBootApplication
public class Application {public static void main(String[] args) {SpringApplication.run(Application.class, args);}/*** 用于接受 shutdown 事件*/@Beanpublic GracefulShutdown gracefulShutdown() {return new GracefulShutdown();}@Beanpublic ServletWebServerFactory servletContainer() {TomcatServletWebServerFactory tomcat = new TomcatServletWebServerFactory();tomcat.addConnectorCustomizers(gracefulShutdown());return tomcat;}/*** 优雅关闭 Spring Boot*/private class GracefulShutdown implements TomcatConnectorCustomizer, ApplicationListener<ContextClosedEvent> {private final Logger log = LoggerFactory.getLogger(GracefulShutdown.class);private volatile Connector connector;private final int waitTime = 30;@Overridepublic void customize(Connector connector) {this.connector = connector;}@Overridepublic void onApplicationEvent(ContextClosedEvent contextClosedEvent) {this.connector.pause();Executor executor = this.connector.getProtocolHandler().getExecutor();if (executor instanceof ThreadPoolExecutor) {try {ThreadPoolExecutor threadPoolExecutor = (ThreadPoolExecutor) executor;threadPoolExecutor.shutdown();if (!threadPoolExecutor.awaitTermination(waitTime, TimeUnit.SECONDS)) {log.warn("Tomcat thread pool did not shut down gracefully within " + waitTime + " seconds. Proceeding with forceful shutdown");}} catch (InterruptedException ex) {Thread.currentThread().interrupt();}}}}}

Undertow 优雅停机

@SpringBootApplication
public class Application {public static void main(String[] args) {SpringApplication.run(Application.class, args);}/*** 优雅关闭 Spring Boot*/@Componentpublic class GracefulShutdown implements ApplicationListener<ContextClosedEvent> {@Autowiredprivate GracefulShutdownWrapper gracefulShutdownWrapper;@Autowiredprivate ServletWebServerApplicationContext context;@Overridepublic void onApplicationEvent(ContextClosedEvent contextClosedEvent){gracefulShutdownWrapper.getGracefulShutdownHandler().shutdown();try {UndertowServletWebServer webServer = (UndertowServletWebServer)context.getWebServer();Field field = webServer.getClass().getDeclaredField("undertow");field.setAccessible(true);Undertow undertow = (Undertow) field.get(webServer);List<Undertow.ListenerInfo> listenerInfo = undertow.getListenerInfo();Undertow.ListenerInfo listener = listenerInfo.get(0);ConnectorStatistics connectorStatistics = listener.getConnectorStatistics();while (connectorStatistics.getActiveConnections() > 0){}}catch (Exception e){// Application Shutdown}}}
}
@Component
public class GracefulShutdownWrapper implements HandlerWrapper{private GracefulShutdownHandler gracefulShutdownHandler;@Overridepublic HttpHandler wrap(HttpHandler handler) {if(gracefulShutdownHandler == null) {this.gracefulShutdownHandler = new GracefulShutdownHandler(handler);}return gracefulShutdownHandler;}public GracefulShutdownHandler getGracefulShutdownHandler() {return gracefulShutdownHandler;}}
@Component
@AllArgsConstructor
public class UndertowExtraConfiguration {private final GracefulShutdownWrapper gracefulShutdownWrapper;@Beanpublic UndertowServletWebServerFactory servletWebServerFactory() {UndertowServletWebServerFactory factory = new UndertowServletWebServerFactory();factory.addDeploymentInfoCustomizers(deploymentInfo -> deploymentInfo.addOuterHandlerChainWrapper(gracefulShutdownWrapper));factory.addBuilderCustomizers(builder -> builder.setServerOption(UndertowOptions.ENABLE_STATISTICS, true));return factory;}}

Jetty 优雅停机

默认支持所有请求完毕后再关闭,缺点:客户端接收不到响应,有待改进!

Spring Boot 内嵌容器 Tomcat / Undertow / Jetty 优雅停机实现相关推荐

  1. Spring Boot 容器选择 Undertow 而不是 Tomcat Spring Boot 内嵌容器Unde

    Spring Boot 内嵌容器Undertow参数设置 配置项: # 设置IO线程数, 它主要执行非阻塞的任务,它们会负责多个连接, 默认设置每个CPU核心一个线程 # 不要设置过大,如果过大,启动 ...

  2. Netweaver的端口号和Spring boot内嵌的Tomcat端口

    Netweaver FM : TH_GET_VIRT_HOST_DATA Spring Boot Spring Boot will launch an embedded Tomcat instance ...

  3. Spring Boot 内嵌容器Undertow参数设置

    配置项: # 设置IO线程数, 它主要执行非阻塞的任务,它们会负责多个连接, 默认设置每个CPU核心一个线程 # 不要设置过大,如果过大,启动项目会报错:打开文件数过多server.undertow. ...

  4. spring boot内嵌tomcat优雅的开启apr模式

    文章目录 简介 Win下开启APR Linux下开启APR 把lib打进jar包 简介 环境: jdk8.spring boot 2.3.4.RELEASE.centOS7.3.win7 在sprin ...

  5. spring boot实战(第七篇)内嵌容器tomcat配置

    spring boot默认web程序启用tomcat内嵌容器tomcat,监听8080端口,servletPath默认为 / 通过需要用到的就是端口.上下文路径的修改,在spring boot中其修改 ...

  6. Spring Boot 内嵌Tomcat的端口号的修改

    操作非常的简单,不过如果从来没有操作过,也是需要查找一下资料的,所以,在此我简单的记录一下自己的操作步骤以备后用! 1:我的Eclipse版本,不同的开发工具可能有所差异,不过大同小异 2:如何进入对 ...

  7. Spring Boot内嵌tomcat关于getServletContext().getRealPath获取得到临时路径的问题

    问题记录 问题场景:修改头像业务,文件上传 代码 // 上传的文件.../upload/文件.png//在javaWeb中我们会用HttpServletRequest来获取上下文路径,当然sessio ...

  8. 修改Spring boot内置的tomcat端口

    介绍两种种简单的修改spring boot内置端口的方法: 第一种:在入口直接设置端口,代码如下所示: public static void main(String[] args){SpringApp ...

  9. 总在说 Spring Boot 内置了 Tomcat 启动,那它的原理你说的清楚吗?

    前言 不得不说SpringBoot的开发者是在为大众程序猿谋福利,把大家都惯成了懒汉,xml不配置了,连tomcat也懒的配置了,典型的一键启动系统,那么tomcat在springboot是怎么启动的 ...

最新文章

  1. php不报错怎么回事,解决PHP 7等web编程语言不报错一例
  2. C# WinForm控件、自定义控件整理(大全)
  3. 【 MATLAB 】fliplr 函数介绍(从左到右翻转阵列)
  4. UA MATH571A 一元线性回归II 统计推断1
  5. Linux下进程通信的八种方法
  6. 第八节: EF的性能篇(一) 之 EF自有方法的性能测试
  7. 安装redis提示[test] error 2_安装PHP Redis扩展
  8. 【HANA系列】SAP HANA Studio出现Fetching Children...问题
  9. linux查看网卡物理编号_Centos 网卡命名规范及信息查看(物理网卡,虚拟网卡)...
  10. sql server 约束 查找
  11. ChromeFFOpera下DIV不设置高度显示背景颜色和边框的办法
  12. 【AIgua小白之路】Windows10安装MySQL10.0.15Archive版 【手把手系列】
  13. 以python项目为例的Pyinstaller打包详细教程
  14. RemObjects SDK ThDataSet总结
  15. iTextSharp 添加文字内容
  16. Proteus仿真:使用8255输出连续方波
  17. 服务器信息批量收集,如何批量导入或导出服务器信息
  18. 靶机-droopyCTF Walkthrough
  19. java浪漫之心代码_浪漫桃心的Android表白程序
  20. ModelSim 与Debussy联调

热门文章

  1. Android中FTP服务器、客户端搭建以及SwiFTP、ftp4j介绍
  2. Java核心技术- Java内存分配原理
  3. 一文读懂VictoriaMetrics集群方案
  4. SpringCloud Alibaba Sentinel 流量控制规则介绍与配置
  5. 统计一个长度为2的子字符串在另一个字符串中出现的次数.例如:假定输入的字符串为“asd asasdfg asd as zx67 asd mklo”,子字符串为“as”,函数返回值为6。
  6. consulAPI服务的注册源码
  7. vue与原生app的对接交互的方法(混合开发)
  8. CSS分别设置Input样式(按input类型
  9. mysql 命令 select_Mysql基础命令(二)select查询操作
  10. 使用Docker安装Redis