SpringBoot:如何调整嵌入式容器的SmartLifecycle阶段优先级
解决方案
要实现计算任务优雅停止后再关闭Web服务器,可以通过调整WebServerGracefulShutdownLifecycle的阶段值来实现,具体步骤如下:
1. 调整Web服务器的生命周期阶段
Spring Boot默认的WebServerGracefulShutdownLifecycle阶段是Integer.MAX_VALUE,我们可以通过BeanPostProcessor在该Bean初始化前修改它的阶段值,让它低于自定义任务的生命周期阶段:
import org.springframework.beans.BeansException; import org.springframework.beans.factory.config.BeanPostProcessor; import org.springframework.boot.web.context.WebServerGracefulShutdownLifecycle; import org.springframework.stereotype.Component; @Component public class WebServerPhaseAdjuster implements BeanPostProcessor { @Override public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException { if (bean instanceof WebServerGracefulShutdownLifecycle) { // 将Web服务器的阶段设为比最大值小100,给自定义任务留出更高阶段 ((WebServerGracefulShutdownLifecycle) bean).setPhase(Integer.MAX_VALUE - 100); } return bean; } }
2. 实现自定义任务的优雅停止生命周期
创建一个SmartLifecycle组件,设置更高的阶段值(比如Integer.MAX_VALUE),确保它的stop()方法在Web服务器关闭前执行,并且在方法内阻塞直到所有计算任务完成:
import org.springframework.context.SmartLifecycle; import org.springframework.stereotype.Component; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; import java.util.concurrent.TimeUnit; @Component public class TaskGracefulShutdown implements SmartLifecycle { private volatile boolean running = false; private final ExecutorService taskExecutor = Executors.newFixedThreadPool(5); @Override public void start() { running = true; // 启动计算任务示例 for (int i = 0; i < 10; i++) { taskExecutor.submit(() -> { try { Thread.sleep(2000); System.out.println("计算任务执行完成"); } catch (InterruptedException e) { Thread.currentThread().interrupt(); } }); } } @Override public void stop() { // 优雅关闭线程池,等待所有任务完成 taskExecutor.shutdown(); try { if (!taskExecutor.awaitTermination(30, TimeUnit.SECONDS)) { taskExecutor.shutdownNow(); } } catch (InterruptedException e) { taskExecutor.shutdownNow(); Thread.currentThread().interrupt(); } System.out.println("所有计算任务已完成,Web服务器即将关闭"); running = false; } @Override public boolean isRunning() { return running; } @Override public int getPhase() { // 设置比Web服务器调整后的阶段更高的值 return Integer.MAX_VALUE; } }
原理说明
Spring的SmartLifecycle停止逻辑是按阶段值从大到小执行:自定义任务的阶段值更高,所以stop()会先被调用,此时Web服务器仍在运行,可正常处理指标、健康检查请求;等自定义任务的stop()执行完毕(即计算任务全部完成),才会执行Web服务器的优雅关闭逻辑。
内容的提问来源于stack exchange,提问作者Azmisov
相关产品推荐
相关产品推荐

