Spring Boot正常关机

Mat*_* I. 5 java spring tomcat spring-boot

我正在开发由嵌入式Tomcat支持的Spring Boot应用程序,并且需要通过以下步骤来正常关闭服务器:

  1. 停止处理新的HTTP请求(停止Web容器)
  2. 处理所有已经接受的请求
  3. 关闭Spring ApplicationContext

*按顺序(依次)执行上述步骤

我该如何实现?

PS Spring Boot 1.5.20.RELEASE,Java 8

Mat*_* I. 7

我已经结束了:

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();
      }
    }
  }
}
Run Code Online (Sandbox Code Playgroud)

一些额外的豆类:

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;
  }
...
Run Code Online (Sandbox Code Playgroud)

  • 具有“类似”解决方案的博客:https://blog.marcosbarbero.com/graceful-shutdown-spring-boot-apps/ 这是用于正常关闭 servlet 容器的 spring boot 问题的链接:https://github .com/spring-projects/spring-boot/issues/4657 (3认同)
  • 看看这个解决方案,我的理解是,它会在请求关闭后强制等待 30 秒,并且只有在 30 秒后才进行正常关闭。但OP也希望停止请求。您的解决方案如何实现这一目标? (2认同)

nar*_*ary 6

Spring Boot 2.3(2020 年 5 月发布)中添加了优雅关闭支持。这允许在关闭上下文和关闭容器之前完成活动请求。

启用优雅关机后,应用程序将在关机时依次执行以下步骤:

  • 停止接受新请求
  • 将等待一些可配置的时间来处理已接受的请求
  • 停止容器
  • 停止嵌入式服务器

发行说明

所有四个嵌入式 Web 服务器(Jetty、Reactor Netty、Tomcat 和 Undertow)以及反应式和基于 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.

对于 Spring Boot < 2.3,您将修改服务器的连接器以停止接受新请求,如Spring GitHub 问题中所述