Spring Boot应用程序的优雅关闭

2023/05/11

1. 概述

在关闭时,默认情况下,Spring的TaskExecutor只是中断所有正在运行的任务,但让它等待所有正在运行的任务完成可能会更好,这为每个任务提供了采取措施以确保关闭安全的机会

在本快速教程中,我们将学习如何在涉及使用线程池执行的任务时更优雅地关闭Spring Boot应用程序。

2. 简单示例

让我们考虑一个简单的Spring Boot应用程序,我们将自动注入默认的TaskExecutor bean:

@Autowired
private TaskExecutor taskExecutor;

在应用程序启动时,让我们使用线程池中的线程执行一个1分钟长的进程:

taskExecutor.execute(() -> {
    Thread.sleep(60_000);
});

当启动关闭时,例如启动后20秒,示例中的线程将被中断,应用程序立即关闭。

3. 等待任务完成

让我们通过创建自定义ThreadPoolTaskExecutor bean来更改任务执行器的默认行为。

此类提供标志setWaitForTasksToCompleteOnShutdown以防止中断正在运行的任务,让我们将其设置为true:

@Bean
public TaskExecutor taskExecutor() {
    ThreadPoolTaskExecutor taskExecutor = new ThreadPoolTaskExecutor();
    taskExecutor.setCorePoolSize(2);
    taskExecutor.setMaxPoolSize(2);
    taskExecutor.setWaitForTasksToCompleteOnShutdown(true);
    taskExecutor.initialize();
    return taskExecutor;
}

而且,我们可以重写之前的逻辑以创建3个线程,每个线程执行一个1分钟长的任务。

@PostConstruct
public void runTaskOnStartup() {
    for (int i = 0; i < 3; i++) {
        taskExecutor.execute(() -> {
            Thread.sleep(60_000);
        });
    }
}

现在让我们在启动后的前60秒内启动关机。我们看到应用程序在启动后仅120秒就关闭了,池大小为2意味着只允许同时执行两个任务,因此第三个任务排队。

设置标志可确保当前正在执行的任务和排队的任务都已完成

请注意,当收到关闭请求时,任务执行器会关闭队列,这样就无法添加新任务

4. 终止前的最长等待时间

尽管我们已经配置为等待正在进行的和排队的任务完成,但Spring会继续关闭容器的其余部分,这可能会释放我们的任务执行器所需的资源并导致任务失败。

为了阻止容器其余部分的关闭,我们可以在ThreadPoolTaskExecutor上指定一个最长等待时间:

taskExecutor.setAwaitTerminationSeconds(30);

这确保在指定的时间段内,容器级别的关闭过程将被阻止

当我们将setWaitForTasksToCompleteOnShutdown标志设置为true时,我们需要指定一个明显更高的超时,以便队列中的所有剩余任务也都得到执行。

5. 总结

在这个快速教程中,我们了解了如何通过配置任务执行器bean来完成运行和提交的任务直到结束,从而安全地关闭Spring Boot应用程序,这保证了所有任务都有指定的时间来完成它们的工作。

一个明显的副作用是它还可能导致更长的关机阶段。因此,我们需要根据应用程序的性质决定是否使用它。

与往常一样,本教程的完整源代码可在GitHub上获得。

Show Disqus Comments

Post Directory

扫码关注公众号:Taketoday
发送 290992
即可立即永久解锁本站全部文章