Spring Boot关闭钩子

时间:2014-10-31 15:29:54

标签: java spring-boot

如何注册/添加一个自定义关闭例程,该例程将在我的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");
        }
    });
}

但是当应用程序关闭时,不会调用此注册的侦听器。

5 个答案:

答案 0 :(得分:22)

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

  

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

     

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

答案 1 :(得分:6)

您的侦听器注册太晚(在上下文已关闭之前永远不会到达该行)。它应该足够@Bean

答案 2 :(得分:3)

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    
   }
}

答案 3 :(得分:2)

您是否尝试过@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 :(得分:1)

我有一个类似的用例,我必须将服务器的关闭过程保持几分钟,我使用了问题中提到的相同方法,唯一的变化是在启动服务后没有添加侦听器,我有在运行应用程序之前添加了侦听器 (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);
    }
}