Spring Boot 內嵌容器 Tomcat / Undertow
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 theDisposableBean
interface or the@PreDestroy
annotation) can be used.
Spring Boot Application 在接收到停機訊號後,可以透過 DisposableBean
介面 、 @PreDestroy
註解 或者 ContextClosedEvent
事件來處理優雅停機的相關邏輯。
版本資訊
Spring Boot 版本: 2.0.0.RELEASE
Tomcat 優雅停機
@SpringBootApplicationpublic 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{ 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 優雅停機
@SpringBootApplicationpublic class Application { public static void main(String[] args) { SpringApplication.run(Application.class, args); } /** * 優雅關閉 Spring Boot */ @Component public class GracefulShutdown implements ApplicationListener{ @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 listenerInfo = undertow.getListenerInfo(); Undertow.ListenerInfo listener = listenerInfo.get(0); ConnectorStatistics connectorStatistics = listener.getConnectorStatistics(); while (connectorStatistics.getActiveConnections() > 0){} }catch (Exception e){ // Application Shutdown } } } }
@Componentpublic 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@AllArgsConstructorpublic 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 優雅停機
預設支援所有請求完畢後再關閉,缺點:客戶端接收不到響應,有待改進!
相關內容
作者:Anoyi
連結:
來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/2819/viewspace-2802432/,如需轉載,請註明出處,否則將追究法律責任。
相關文章
- 精盡Spring Boot原始碼分析 - 內嵌Tomcat容器的實現Spring Boot原始碼Tomcat
- Spring Boot移除內嵌Tomcat,使用非web方式啟動Spring BootTomcatWeb
- Netweaver的埠號和Spring boot內嵌的Tomcat埠Spring BootTomcat
- spring-boot定製和最佳化內嵌的TomcatSpringbootTomcat
- 學習Tomcat(七)之Spring內嵌TomcatTomcatSpring
- SpringBoot原始碼解析-內嵌Tomcat容器的啟動Spring Boot原始碼Tomcat
- 【Spring】內嵌Tomcat&去Xml&除錯MvcSpringTomcatXML除錯MVC
- spring boot 載入web容器tomcat流程原始碼分析Spring BootWebTomcat原始碼
- Spring Boot 揭祕與實戰(五) 伺服器篇 – 內嵌的伺服器 Tomcat剖析 | 掘金技術徵文Spring Boot伺服器Tomcat
- Spring Boot 揭祕與實戰(五) 伺服器篇 - 內嵌的伺服器 Tomcat剖析 | 掘金技術徵文Spring Boot伺服器Tomcat
- Spring Boot學習5:spring-boot web容器Spring BootWeb
- spring boot 配置外接tomcatSpring BootTomcat
- 精盡Spring Boot原始碼分析 - 支援外部 Tomcat 容器的實現Spring Boot原始碼Tomcat
- spring boot 部署到線上tomcatSpring BootTomcat
- [Web Server]Tomcat調優之SpringBoot內嵌Tomcat原始碼分析WebServerTomcatSpring Boot原始碼
- spring boot(7) 配置外部tomcat(1)Spring BootTomcat
- Linux環境下Spring Boot專案內建Tomcat引數配置LinuxSpring BootTomcat
- spring boot基於Java的容器配置Spring BootJava
- Spring Boot專案部署到外部TomcatSpring BootTomcat
- SpringBoot2.0之Servlet容器變成UndertowSpring BootServlet
- Spring Boot —— Thymeleaf + Gradle run on Tomcat(war形式)Spring BootGradleTomcat
- Spring Boot 開箱即用,內藏玄機Spring Boot
- Nginx 內嵌變數Nginx變數
- spring內嵌cglib包,這裡藏著一個大坑SpringCGLib
- Spring Boot中Tomcat是怎麼啟動的Spring BootTomcat
- 在外部tomcat中執行spring boot應用TomcatSpring Boot
- 探析 Spring 容器內部事件釋出Spring事件
- Spring Boot 容器化踩坑與解決方案(1)Spring Boot
- 十二、Spring Boot 嵌入式 Servlet 容器啟動原理Spring BootServlet
- 如何訪問Docker容器中的Spring Boot日誌DockerSpring Boot
- MongoDB查詢內嵌文件MongoDB
- Spring Boot 學習系列(11)—tomcat引數配置建Spring BootTomcat
- 聊聊spring boot tomcat jdbc pool的屬性繫結Spring BootTomcatJDBC
- 淺談小程式內嵌網頁及內嵌網頁跳轉分享實現網頁
- 把spring-boot專案部署到tomcat中的方法SpringbootTomcat
- Web Socket 效能對比——Spring Boot vs Tomcat vs NettyWebSpring BootTomcatNetty
- spring-boot專案在外部tomcat環境下部署SpringbootTomcat
- 小程式內嵌h5H5