【问题标题】:Spring Boot shutdown hookSpring Boot 关闭钩子
【发布时间】:2014-12-27 23:34:29
【问题描述】:

如何注册/添加一个自定义关闭例程,该例程在我的 Spring Boot 应用程序关闭时触发?

场景:我将 Spring Boot 应用程序部署到 Jetty servlet 容器(即,没有嵌入式 Jetty)。我的应用程序使用 Logback 进行日志记录,我想在运行时使用 Logback 的 MBean JMX 配置器更改日志记录级别。 Its documentation states that to avoid memory leaks, on shutdown a specific LoggerContext shutdown method has to be called.

监听 Spring Boot 关闭事件的好方法是什么?

我试过了:

public static void main(String[] args) throws Exception {
    ConfigurableApplicationContext cac = SpringApplication.run(Example.class, args);

    cac.addApplicationListener(new ApplicationListener<ContextClosedEvent>() {

        @Override
        public void onApplicationEvent(ContextClosedEvent event) {
            logger.info("Do something");
        }
    });
}

但是当应用程序关闭时,这个注册的监听器不会被调用。

【问题讨论】:

标签: java spring-boot


【解决方案1】:

https://docs.spring.io/spring-boot/docs/current-SNAPSHOT/reference/htmlsingle/#features.spring-application.application-exit

每个 SpringApplication 都会向 JVM 注册一个关闭钩子,以确保 ApplicationContext 在退出时正常关闭。所有标准的 Spring 生命周期回调(例如 DisposableBean 接口,或 @PreDestroy 注解)都可以使用。

此外,如果希望在应用程序结束时返回特定的退出代码,bean 可以实现 org.springframework.boot.ExitCodeGenerator 接口。

【讨论】:

【解决方案2】:

我有一个类似的用例,我必须保持服务器的关闭过程几分钟,我使用了问题中提到的相同方法,唯一的变化是在启动服务后添加侦听器,我有在运行应用程序之前添加了监听器(ContextClosedEvent


@SpringBootApplication
public class Application {

    public static void main(String[] args) {
        SpringApplication application = new SpringApplication(Application.class);
        application.addListeners((ApplicationListener<ContextClosedEvent>) event -> {
            log.info("Shutdown process initiated...");
            try {
                Thread.sleep(TimeUnit.MINUTES.toMillis(5));
            } catch (InterruptedException e) {
                log.error("Exception is thrown during the ContextClosedEvent", e);
            }
            log.info("Graceful Shutdown is processed successfully");
        });
        application.run(args);
    }
}

【讨论】:

    【解决方案3】:

    您是否尝试过 @cfrick 提到的这个?

    @SpringBootApplication
    @Slf4j
    public class SpringBootShutdownHookApplication {
    
      public static void main(String[] args) {
        SpringApplication.run(SpringBootShutdownHookApplication.class, args);
      }
    
      @PreDestroy
      public void onExit() {
        log.info("###STOPing###");
        try {
          Thread.sleep(5 * 1000);
        } catch (InterruptedException e) {
          log.error("", e);;
        }
        log.info("###STOP FROM THE LIFECYCLE###");
      }
    }
    

    【讨论】:

      【解决方案4】:
      import org.springframework.boot.SpringApplication;
      import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
      import org.springframework.boot.autoconfigure.SpringBootApplication;
      import org.springframework.boot.web.servlet.ServletListenerRegistrationBean;
      import org.springframework.boot.web.support.SpringBootServletInitializer;
      import org.springframework.context.annotation.Bean;
      
      @SpringBootApplication
      @EnableAutoConfiguration
      public class Application extends SpringBootServletInitializer {
      
          public static void main(
                  String[] args) {
              SpringApplication.run(Application.class,
                                    args);
          }
      
          @NotNull
          @Bean
          ServletListenerRegistrationBean<ServletContextListener> myServletListener() {
              ServletListenerRegistrationBean<ServletContextListener> srb =
                      new ServletListenerRegistrationBean<>();
              srb.setListener(new ExampleServletContextListener());
              return srb;
          }
      }
      
       import javax.servlet.ServletContextEvent;
       import javax.servlet.ServletContextListener;
      
       public class ExampleServletContextListener implements ServletContextListener {
          @Override
          public void contextInitialized(
              ServletContextEvent sce) {
          // Context Initialised
          }
      
          @Override
          public void contextDestroyed(
              ServletContextEvent sce) {
             // Here - what you want to do that context shutdown    
         }
      }
      

      【讨论】:

        【解决方案5】:

        您的侦听器注册得太晚(在上下文关闭之前永远不会到达该行)。将其设为@Bean 就足够了。

        【讨论】:

          猜你喜欢
          • 2018-01-23
          • 2023-03-19
          • 1970-01-01
          • 2018-09-03
          • 1970-01-01
          • 1970-01-01
          • 2015-06-11
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多