`
QING____
  • 浏览: 2233188 次
  • 性别: Icon_minigender_1
  • 来自: 北京
社区版块
存档分类
最新评论

Springboot 2.x优雅关闭tomcat容器

    博客分类:
  • JAVA
阅读更多

    1、如果你的springboot应用打包成“可执行jar”,我们通过可以借助springboot launchscript优雅关闭。

    2、如果你的springboot应用是普通jar,通过“java -jar”启动,那么优雅关闭的方式需要外部脚本去控制。

 

    不过无论如何,我们希望做一件事情,就是在应用即将退出之前,关闭tomcat时,让tomcat不再接收新请求、但是已经接收的请求尽可能执行完毕。

 

    为了达成这个设计目标,我们需要自定义tomcat链接器设置,主要思想是:当应用发出ContextClosedEvent时,关闭tomcat的链接处理器(即不再接收新请求),同时等待一段时间直到已有请求处理完毕,然后关闭内部的链接池、线程池。

 

import org.apache.catalina.connector.Connector;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.apache.coyote.ProtocolHandler;
import org.apache.tomcat.util.threads.ThreadPoolExecutor;
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.TimeUnit;

/**
 * @author liuguanqing
 * created 2019/1/18 12:25 PM
 **/
public class MeteorTomcatConnectorCustomizer implements TomcatConnectorCustomizer, ApplicationListener<ContextClosedEvent> {

    private volatile Connector connector;

    private static final int WAIT_TIMEOUT = 3000;//6S

    private static final int MAX_WAIT_TIMEOUT = 12000;

    protected static final Log logger = LogFactory.getLog(MeteorTomcatConnectorCustomizer.class);

    @Override
    public void customize(Connector connector) {
        this.connector = connector;
    }

    @Override
    public void onApplicationEvent(ContextClosedEvent event) {
        if (this.connector == null) {
            logger.warn("Tomcat connector has'nt been ready!");
        }
        ProtocolHandler protocolHandler = this.connector.getProtocolHandler();
        try {
            Executor executor = protocolHandler.getExecutor();
            protocolHandler.stop();//执行关闭流程,此关闭流程中不会关闭外部指定的executer
            //非tomcat内置的executor,建议单独关闭
            if (executor instanceof ThreadPoolExecutor) {
                try {
                    ThreadPoolExecutor threadPoolExecutor = (ThreadPoolExecutor) executor;
                    int i = 0;
                    while (i < MAX_WAIT_TIMEOUT && !threadPoolExecutor.isShutdown()) {
                        threadPoolExecutor.shutdown();
                        if (!threadPoolExecutor.awaitTermination(WAIT_TIMEOUT, TimeUnit.MILLISECONDS)) {
                            i += WAIT_TIMEOUT;
                            logger.warn("Tomcat thread pool will be shutdown,total waiting-time=[" + i + "ms]");
                        }
                    }
                    if (!threadPoolExecutor.isShutdown()) {
                        threadPoolExecutor.shutdownNow();
                        if (!threadPoolExecutor.awaitTermination(WAIT_TIMEOUT, TimeUnit.MILLISECONDS)) {
                            logger.error("Tomcat thread pool did not terminate,shutdown failed!");
                        }
                    } else {
                        logger.info("Tomcat thread pool has been shutdown successfully!");
                    }
                } catch (InterruptedException ex) {
                    Thread.currentThread().interrupt();
                }
            }
        } catch (Exception e) {
            logger.error("Tomcat shutdown error!",e);
        }
    }

}

 

分享到:
评论

相关推荐

Global site tag (gtag.js) - Google Analytics