Spring Boot如何内嵌容器Tomcat/Undertow/Jetty优雅停机呢?

欣喜 SpringBoot 发布时间:2024-02-06 14:05:16 阅读数:7130 1
下文笔者讲述SpringBoot内嵌容器Tomcat/Undertow/Jetty停机时的业务逻辑处理方法分享,如下所示

Springboot关闭时-简介说明

 
我们都知道Spring Boot关闭时
   如果有请求没有响应完
      在不同的容器会出现不同的结果

如:
   在Tomcat和Undertow中会出现中断异常
    那么就有可能对业务造成影响
  所以我们必须采用合理的方式进行SpringBoot停机
========================================
在SpringBoot中我们在接收到停机信号之后
   可通过实现DisposableBean 接口 、 @PreDestroy 注解 或者 ContextClosedEvent 事件
       来处理关闭后的相关事件
例:

Tomcat优雅停机

@SpringBootApplication
public class Application {

    public static void main(String[] args) {
        SpringApplication.run(Application.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 class GracefulShutdown implements TomcatConnectorCustomizer, Applicationlistener<ContextClosedEvent> {
        private final Logger log = LoggerFactory.getLogger(GracefulShutdown.class);
        private volatile Connector connector;
        private final int waitTime = 30;
        @Override
        public void customize(Connector connector) {
            this.connector = connector;
        }
        @Override
        public 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
     */
    @Component
    public class GracefulShutdown implements ApplicationListener<ContextClosedEvent> {

        @Autowired
        private GracefulShutdownWrapper gracefulShutdownWrapper;

        @Autowired
        private ServletWebServerApplicationContext context;

        @Override
        public 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;

    @Override
    public 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;

    @Bean
    public UndertowServletWebServerFactory servletWebServerFactory() {
        UndertowServletWebServerFactory factory = new UndertowServletWebServerFactory();
        factory.addDeploymentInfoCustomizers(deploymentInfo -> deploymentInfo.addOuterHandlerChainWrapper(gracefulShutdownWrapper));
        factory.addBuilderCustomizers(builder -> builder.setServerOption(UndertowOptions.ENABLE_STATISTICS, true));
        return factory;
    }

}

Jetty 优雅停机

默认支持所有请求完毕后再关闭
缺点:客户端接收不到响应
版权声明

本文仅代表作者观点,不代表本站立场。
本文系作者授权发表,未经许可,不得转载。

本文链接: https://www.Java265.com/JavaFramework/SpringBoot/202402/7922.html

最近发表

热门文章

好文推荐

Java265.com

https://www.java265.com

站长统计|粤ICP备14097017号-3

Powered By Java265.com信息维护小组

使用手机扫描二维码

关注我们看更多资讯

java爱好者