如何注册/添加一个自定义关闭例程,该例程将在我的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");
}
});
}
但是当应用程序关闭时,不会调用此注册的侦听器。
答案 0 :(得分:22)
每个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);
}
}