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

发布时间:2026/7/26 22:50:50

Spring Boot 内嵌容器 Tomcat / Undertow / Jetty 优雅停机实现 前言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 事件来处理优雅停机的相关逻辑。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, ApplicationListenerContextClosedEvent { 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 ApplicationListenerContextClosedEvent { 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); ListUndertow.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 优雅停机默认支持所有请求完毕后再关闭缺点客户端接收不到响应有待改进 福利时间如果你正在备战面试或者想要学习其他知识给大家推荐一个宝藏知识库作者整理了一些列 Java 程序员需要掌握的核心知识有需要的自取不谢。知识库地址https://farerboy.com/

相关新闻