SpringBoot如何优雅关闭(SpringBoot2.3&Spring Boot2.2)-编程思维

SpringBoot如何优雅关闭(SpringBoot2.3&Spring Boot2.2)

优雅停止&暴力停止

  • 暴力停止:像日常开发过程中,测试区或者本地开发时,我们并不会考虑项目关闭带来的影响,只是想最快速的关掉重启,所以用的最多的就是kill -9进行暴力停止服务;kill -9的结果就是强制关闭,不会等待服务释放资源等操作,这也造成了,服务中很多进程无法正常结束。
  • 优雅停止:何谓优雅停止,就是等待已有的进程结束之后关闭服务,那么如何实现优雅停止SpringBoot服务?

实现优雅停止

SpringBoot要实现优雅停止,分两种情况一个是SpringBoot版本为2.3.0之前,一种是2.3.0及往后的版本。

  • SpringBoot 2.3.0及后续版本

    在SpringBoot的ReleaseNotes中我们可以看到,在2.3.0版本,SpringBoot新特性中有一个叫GraceFul shutdown的字样。

    意思就是,可以通过配置server.shutdown来实现优雅关闭SpriingBoot服务,支持内嵌的Jetty,Reactor,Netty,Undertow服务器,在配置了优雅停止的情况下关闭服务,服务将不会接收后续请求, 并且会等待宽限期,以便完成当前已有请求。

    配置解释:

    1. server.shutdown : graceful : 表示开启优雅停止
    2. spring.lifecycle.timeout-per-shutdown-phase : 60 :表示最大等待的宽限时间,超过这个时间还有请求没结束的话,会强制关闭服务。

    注意:这里需要注意的是,不能使用kill -9的命令停止服务,不然优雅停止的配置不会生效。

  • SpringBoot2.3.0之前的版本

    在上述的ReleaseNotes看到,配置的方式实现优雅停止时2.3.0之后才有的功能,那往前的版本怎么办?自己手动写。

    @Slf4j
    @SpringBootApplication(exclude = DataSourceAutoConfiguration.class)
    public class NginxTestApplication {
    
        public static void main(String[] args) {
            SpringApplication.run(NginxTestApplication.class, args);
        }
    
        /**
         * 用于接受 shutdown 事件
         */
        @Bean
        public GracefulShutdown gracefulShutdown() {
            return new GracefulShutdown();
        }
    
        @Bean
        public ServletWebServerFactory servletContainer() {
            TomcatServletWebServerFactory tomcat = new TomcatServletWebServerFactory();
            tomcat.addConnectorCustomizers(gracefulShutdown());
            return tomcat;
        }
    
        /**
         * 优雅关闭 Spring Boot
         */
        private static class GracefulShutdown implements TomcatConnectorCustomizer, ApplicationListener<ContextClosedEvent> {
            private volatile Connector connector;
    
    
            //获取tomcat的connector
            @Override
            public void customize(Connector connector) {
                this.connector = connector;
            }
    
            //监听事件
            @Override
            public void onApplicationEvent(ContextClosedEvent contextClosedEvent) {
                //拒绝停机操作的后续请求
                this.connector.pause();
                log.info("停止Tomcat connector, 拒绝接收后续请求");
                //获取对应线程池并做对应类型判断,true则开始优雅关闭
                Executor executor = this.connector.getProtocolHandler().getExecutor();
                if (executor instanceof ThreadPoolExecutor) {
                    try {
                        ThreadPoolExecutor threadPoolExecutor = (ThreadPoolExecutor) executor;
                        //开始关闭线程池
                        threadPoolExecutor.shutdown();
                        log.info("开始关闭线程池");
                        //最大宽限时间
                        int waitTime = 30;
                        //若线程池中有未完成事件,等待完成后关闭,若超过最大宽限时间未完成,强制关闭;
                        //若没有未完成事件,直接关闭
                        if (!threadPoolExecutor.awaitTermination(waitTime, TimeUnit.SECONDS)) {
                            log.info("Tomcat线程池无法在"+waitTime+"s 内优雅关闭. 强制结束");
                        }
                    } catch (InterruptedException ex) {
                        Thread.currentThread().interrupt();
                    }
                }
            }
        }
    
    }
    

    在启动类中加上这些东西就行了,写了很多注释,就不详细解释了。

    注意:这里同样需要注意的是,不能使用kill -9的命令停止服务,不然优雅停止不会生效。

版权声明:本文版权归作者所有,遵循 CC 4.0 BY-SA 许可协议, 转载请注明原文链接
https://www.cnblogs.com/liuxiankai/p/16242466.html

撸了一个 Feign 增强包 V2.0 升级版-编程思维

前言 大概在两年前我写过一篇 撸了一个 Feign 增强包,当时准备是利用 SpringBoot + K8s 构建应用,这个库可以类似于 SpringCloud 那样结合 SpringBoot 使用声明式接口来达到服务间通讯的目的。 但后期由于技术栈发生变化(改为 Go),导致该项目只实现了基本需求后就搁置了。 巧合的

【Java分享客栈】超简洁SpringBoot使用AOP统一日志管理-纯干货干到便秘-编程思维

前言 请问今天您便秘了吗?程序员坐久了真的会便秘哦,如果偶然点进了这篇小干货,就麻烦您喝杯水然后去趟厕所一边用左手托起对准嘘嘘,一边用右手滑动手机看完本篇吧。 实现 本篇AOP统一日志管理写法来源于国外知名开源框架JHipster的AOP日志管理方式 1、引入依赖 <!-- spring aop --&g

MyBatisPlus实现分页和查询操作就这么简单-编程思维

《SpringBoot整合MybatisPlus基本的增删改查,保姆级教程》在这篇文章中,我们详细介绍了分页的具体实现方法。但是,在日常的开发中还需要搜索功能的。下面让我们一起动起手来,实现一下吧。 定义查询字段 定义一个类,存放需要用到的查询字段。如下: package com.didiplus.modules.s

【Java分享客栈】超简洁SpringBoot使用AOP统一日志管理-纯干货干到便秘-编程思维

前言 请问今天您便秘了吗?程序员坐久了真的会便秘哦,如果偶然点进了这篇小干货,就麻烦您喝杯水然后去趟厕所一边用左手托起对准嘘嘘,一边用右手滑动手机看完本篇吧。 实现 本篇AOP统一日志管理写法来源于国外知名开源框架JHipster的AOP日志管理方式 1、引入依赖 <!-- spring aop --&g

Redis限制一键登录次数-编程思维

一、产生背景 之前的随笔提到过项目中写了一键登录功能、上线后除了有时候网络波动会导致登陆失败,其他情况一直稳如老狗 しかし,邮件看到有人恶意刷一键登录,这年头闲的人可真闲啊, 只能思考如何搞一搞 二、解决思路 因为项目实现一键登录采用的是 自有服务器调用 所以限制一键登录分为两步走,因为每个手机号有唯一的openi