Spring Boot关机钩子

67

如何在Spring Boot应用程序关闭时注册/添加自定义关闭路由?

场景:我将Spring Boot应用程序部署到Jetty servlet容器中(即没有嵌入式Jetty)。 我的应用程序使用Logback进行日志记录,并且我想在运行时使用Logback的MBean JMX配置器更改日志记录级别。 其文档指出,为了避免内存泄漏,在关闭时必须调用特定的LoggerContext关闭方法

有哪些监听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");
        }
    });
}

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


3
在创建上下文之后注册侦听器基本上是无用的。如果您希望它参与进来,您需要像任何其他bean一样在应用程序上下文中将其注册为bean。 - M. Deinum
这个回答解决了你的问题吗?Spring是否有关闭进程来执行清理代码的功能? - Jason Law
5个回答

42

我已更新我的问题,展示了我目前不成功的努力。 - Abdull
2
更新链接 https://docs.spring.io/spring-boot/docs/current/reference/html/boot-features-spring-application.html#boot-features-application-exit - Kenny
1
精确的选项卡链接:https://docs.spring.io/spring-boot/docs/current/reference/html/features.html#features.spring-application.application-exit - Jabongg

35

你尝试过 @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###");
  }
}

10
您的监听器注册太晚了(该行代码直到上下文已经关闭才会被执行)。将其设置为@Bean应该就足够了。

5

我有一个类似的用例,需要将服务器的关闭过程暂停几分钟,我使用了问题中提到的相同方法,唯一的区别是在运行应用程序之前添加了监听器(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);
    }
}

你必须在catch中恢复中断标志。 - Simon Logic

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

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接