我正在开发一个由嵌入式Tomcat支持的Sping Boot 应用程序,我需要通过以下步骤开发一个优雅的关机:1.停止处理新的HTTP请求(停止Web容器)1.处理所有已接受的请求
我如何才能做到这一点?P.S. Sping Boot 1.5.20.RELEASE,Java 8
mo49yndu1#
Sping Boot 2.3(2020年5月发布)中添加了优雅关闭支持。这允许活动请求在关闭上下文和关闭容器之前完成。当启用优雅关机时,应用程序将在关机时按顺序执行以下步骤:
来自Release Notes:所有四个嵌入式Web服务器(Jetty、Reactor Netty、Tomcat和Undertow)以及React式和基于Servlet的Web应用程序都支持优雅关闭。当使用server.shutdown=graceful启用时,在关闭时,Web服务器将不再允许新请求,并将等待宽限期以完成活动请求。可以使用spring.lifecycle.timeout-per-shutdown-phase配置宽限期。
server.shutdown=graceful
spring.lifecycle.timeout-per-shutdown-phase
immediate
spring.lifecycle.timeout-per-shutdown-phase=1m
对于< 2.3的Sping Boot ,您需要修改服务器的连接器以停止接受新请求,如this Spring GitHub issue中所述。
vatpfxk52#
我最终得到了:
import java.util.concurrent.Executor; import java.util.concurrent.ThreadPoolExecutor; import java.util.concurrent.TimeUnit; import org.apache.catalina.connector.Connector; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.boot.context.embedded.tomcat.TomcatConnectorCustomizer; import org.springframework.context.ApplicationListener; import org.springframework.context.event.ContextClosedEvent; public class GracefulShutdown implements TomcatConnectorCustomizer, ApplicationListener<ContextClosedEvent> { private static final Logger log = LoggerFactory.getLogger(GracefulShutdown.class); private volatile Connector connector; @Override public void customize(Connector connector) { this.connector = connector; } @Override public void onApplicationEvent(ContextClosedEvent contextClosedEvent) { log.info("Protocol handler is shutting down"); this.connector.pause(); Executor executor = this.connector.getProtocolHandler().getExecutor(); if (executor instanceof ThreadPoolExecutor) { try { ThreadPoolExecutor threadPoolExecutor = (ThreadPoolExecutor) executor; threadPoolExecutor.shutdown(); if (!threadPoolExecutor.awaitTermination(30, TimeUnit.SECONDS)) log.warn("Tomcat thread pool did not shut down gracefully within 30 seconds. Proceeding with forceful shutdown"); else log.info("Protocol handler shut down"); } catch (InterruptedException e) { Thread.currentThread().interrupt(); } } } }
更多的豆:
import org.springframework.boot.context.embedded.EmbeddedServletContainerFactory; import org.springframework.boot.context.embedded.tomcat.TomcatEmbeddedServletContainerFactory; ... @Bean public GracefulShutdown gracefulShutdown() { return new GracefulShutdown(); } @Bean public EmbeddedServletContainerFactory servletContainer(final GracefulShutdown gracefulShutdown) { TomcatEmbeddedServletContainerFactory factory = new TomcatEmbeddedServletContainerFactory(); factory.addConnectorCustomizers(gracefulShutdown); return factory; } ...
7uhlpewt3#
它的简单,Spring Boot 本身提供的功能。https://docs.spring.io/spring-boot/docs/current/reference/htmlsingle/#boot-features-application-exit
void shoutdown(){ System.out.println("====+= Shoutdown +++==="); System.exit(SpringApplication.exit(apc, this.exitCodeGenerator())); }
在输出中可以看到,所有当前线程都被关闭。输出量:=+= Shoutdown +==
2020-06-09 11:21:45,543 DEBUG[main][c.u.j.c.EnableEncryptablePropertiesBeanFactoryPostProcessor] Application Event Raised: ExitCodeEvent 2020-06-09 11:21:45,543 DEBUG[main][c.u.j.c.EnableEncryptablePropertiesBeanFactoryPostProcessor] Application Event Raised: ExitCodeEvent 2020-06-09 11:21:45,546 DEBUG[main][c.u.j.c.EnableEncryptablePropertiesBeanFactoryPostProcessor] Application Event Raised: ContextClosedEvent 2020-06-09 11:21:45,546 DEBUG[main][c.u.j.c.EnableEncryptablePropertiesBeanFactoryPostProcessor] Application Event Raised: ContextClosedEvent 2020-06-09 11:21:45,547 INFO [main][o.a.kafka.clients.producer.KafkaProducer] [Producer clientId=producer-1] Closing the Kafka producer with timeoutMillis = 30000 ms. 2020-06-09 11:21:45,548 DEBUG[kafka-producer-network-thread | producer-1][o.a.k.clients.producer.internals.Sender] [Producer clientId=producer-1] Beginning shutdown of Kafka producer I/O thread, sending remaining records. 2020-06-09 11:21:45,551 DEBUG[kafka-producer-network-thread | producer-1][org.apache.kafka.common.metrics.Metrics] Removed sensor with name connections-closed: 2020-06-09 11:21:45,554 DEBUG[kafka-producer-network-thread | producer-1][org.apache.kafka.common.metrics.Metrics] Removed sensor with name connections-created: 2020-06-09 11:21:45,554 DEBUG[kafka-producer-network-thread | producer-1][org.apache.kafka.common.metrics.Metrics] Removed sensor with name successful-authentication: 2020-06-09 11:21:45,558 DEBUG[kafka-producer-network-thread | producer-1][org.apache.kafka.common.metrics.Metrics] Removed sensor with name failed-authentication: 2020-06-09 11:21:45,558 DEBUG[kafka-producer-network-thread | producer-1][org.apache.kafka.common.metrics.Metrics] Removed sensor with name bytes-sent-received: 2020-06-09 11:21:45,559 DEBUG[kafka-producer-network-thread | producer-1][org.apache.kafka.common.metrics.Metrics] Removed sensor with name bytes-sent: 2020-06-09 11:21:45,559 DEBUG[kafka-producer-network-thread | producer-1][org.apache.kafka.common.metrics.Metrics] Removed sensor with name bytes-received: 2020-06-09 11:21:45,560 DEBUG[kafka-producer-network-thread | producer-1][org.apache.kafka.common.metrics.Metrics] Removed sensor with name select-time: 2020-06-09 11:21:45,561 DEBUG[kafka-producer-network-thread | producer-1][org.apache.kafka.common.metrics.Metrics] Removed sensor with name io-time: 2020-06-09 11:21:45,570 DEBUG[kafka-producer-network-thread | producer-1][org.apache.kafka.common.metrics.Metrics] Removed sensor with name node--1.bytes-sent 2020-06-09 11:21:45,570 DEBUG[kafka-producer-network-thread | producer-1][org.apache.kafka.common.metrics.Metrics] Removed sensor with name node--1.bytes-received 2020-06-09 11:21:45,570 DEBUG[kafka-producer-network-thread | producer-1][org.apache.kafka.common.metrics.Metrics] Removed sensor with name node--1.latency 2020-06-09 11:21:45,571 DEBUG[kafka-producer-network-thread | producer-1][org.apache.kafka.common.metrics.Metrics] Removed sensor with name node-0.bytes-sent 2020-06-09 11:21:45,571 DEBUG[kafka-producer-network-thread | producer-1][org.apache.kafka.common.metrics.Metrics] Removed sensor with name node-0.bytes-received 2020-06-09 11:21:45,573 DEBUG[kafka-producer-network-thread | producer-1][org.apache.kafka.common.metrics.Metrics] Removed sensor with name node-0.latency 2020-06-09 11:21:45,573 DEBUG[kafka-producer-network-thread | producer-1][o.a.k.clients.producer.internals.Sender] [Producer clientId=producer-1] Shutdown of Kafka producer I/O thread has completed. 2020-06-09 11:21:45,607 DEBUG[main][o.a.kafka.clients.producer.KafkaProducer] [Producer clientId=producer-1] Kafka producer has been closed 2020-06-09 11:21:45,611 DEBUG[main][o.hibernate.internal.SessionFactoryImpl] HHH000031: Closing 2020-06-09 11:21:45,611 DEBUG[main][o.h.type.spi.TypeConfiguration$Scope] Un-scoping TypeConfiguration [org.hibernate.type.spi.TypeConfiguration$Scope@5dfd31f4] from SessionFactory [org.hibernate.internal.SessionFactoryImpl@62a54948] 2020-06-09 11:21:45,612 DEBUG[main][o.h.s.i.AbstractServiceRegistryImpl] Implicitly destroying ServiceRegistry on de-registration of all child ServiceRegistries 2020-06-09 11:21:45,613 DEBUG[main][o.h.b.r.i.BootstrapServiceRegistryImpl] Implicitly destroying Boot-strap registry on de-registration of all child ServiceRegistries 2020-06-09 11:21:45,613 INFO [main][com.zaxxer.hikari.HikariDataSource] HikariPool-1 - Shutdown initiated... 2020-06-09 11:21:45,754 INFO [main][com.zaxxer.hikari.HikariDataSource] HikariPool-1 - Shutdown completed.
3条答案
按热度按时间mo49yndu1#
Sping Boot 2.3(2020年5月发布)中添加了优雅关闭支持。这允许活动请求在关闭上下文和关闭容器之前完成。
当启用优雅关机时,应用程序将在关机时按顺序执行以下步骤:
来自Release Notes:
所有四个嵌入式Web服务器(Jetty、Reactor Netty、Tomcat和Undertow)以及React式和基于Servlet的Web应用程序都支持优雅关闭。当使用
server.shutdown=graceful
启用时,在关闭时,Web服务器将不再允许新请求,并将等待宽限期以完成活动请求。可以使用spring.lifecycle.timeout-per-shutdown-phase
配置宽限期。server.shutdown=graceful
添加到属性(默认情况下设置为immediate
)。spring.lifecycle.timeout-per-shutdown-phase
属性配置宽限期(例如:spring.lifecycle.timeout-per-shutdown-phase=1m
。对于< 2.3的Sping Boot ,您需要修改服务器的连接器以停止接受新请求,如this Spring GitHub issue中所述。
vatpfxk52#
我最终得到了:
更多的豆:
7uhlpewt3#
它的简单,Spring Boot 本身提供的功能。https://docs.spring.io/spring-boot/docs/current/reference/htmlsingle/#boot-features-application-exit
在输出中可以看到,所有当前线程都被关闭。输出量:
=+= Shoutdown +==