如何在 Web 应用程序中的所有其他 bean 被销毁之前关闭 Spring 任务执行程序/调度程序池? [英] How can I shutdown Spring task executor/scheduler pools before all other beans in the web app are destroyed?

查看:21
本文介绍了如何在 Web 应用程序中的所有其他 bean 被销毁之前关闭 Spring 任务执行程序/调度程序池?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

在 Spring Web 应用程序中,我有几个 DAO 和服务层 bean.一个服务层 bean 已经注释了 @Async/@Scheduled 方法.这些方法依赖于其他(自动装配的)bean.我在 XML 中配置了两个线程池:

In a Spring web application I have several DAO and service layer beans. One service layer bean has annotated @Async / @Scheduled methods. These methods depend on other (autowired) beans. I have configured two thread pools in XML:

<bean id="taskExecutor" class="org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor">
     <property name="corePoolSize" value="2" />
     <property name="maxPoolSize" value="5" />
     <property name="queueCapacity" value="5" />
     <property name="waitForTasksToCompleteOnShutdown" value="true" />
     <property name="rejectedExecutionHandler">
            <bean class="java.util.concurrent.ThreadPoolExecutor$CallerRunsPolicy"/>
        </property>
    </bean>

<bean id="taskScheduler" class="org.springframework.scheduling.concurrent.ThreadPoolTaskScheduler">
     <property name="poolSize" value="10" />
     <property name="waitForTasksToCompleteOnShutdown" value="true" />
     <property name="rejectedExecutionHandler">
            <bean class="java.util.concurrent.ThreadPoolExecutor$CallerRunsPolicy"/>
        </property>
    </bean>

    <task:annotation-driven executor="taskExecutor" scheduler="taskScheduler"/>

一切都按预期进行.我的问题是我无法完全关闭任务池来工作.这些任务在数据库和文件系统上运行.当我停止 Web 应用程序时,它需要一些时间才能停止.这表明 waitForTasksToCompleteOnShutdown 属性有效.但是,我在日志中收到 IllegalStateExceptions,表明某些 bean 已被销毁,但某些工作任务线程仍在执行,并且由于它们的依赖项被销毁而失败.

Everything works as expected. My problem is that I cannot get a clean shutdown of the task pools to work. The tasks operate on the database and on the file system. When I stop the web application it takes some time until it is stopped. This indicates that the waitForTasksToCompleteOnShutdown property works. However, I get IllegalStateExceptions in the log indicating that some beans are already destroyed but some worker task threads are still executing and they fail because their dependencies are destroyed.

有一个可能相关的 JIRA 问题:SPR-5387

There is a JIRA issue which might be relevant: SPR-5387

我的问题是:有没有办法告诉 Spring 最后初始化任务执行程序/调度程序 bean,或者有没有办法告诉 Spring 先销毁它们?

我的理解是销毁以相反的初始化顺序发生.因此最后初始化的 bean 将首先被销毁.如果先销毁线程池 bean,则所有当前正在执行的任务都将完成并且仍然可以访问依赖 bean.

My understanding is that destruction takes place in reversed init order. Therefore the bean init'ed last will be destroyed first. If the thread pool beans are destroyed first, all currently executing tasks would finish and could still access dependent beans.

我还尝试在引用我的服务 bean 的线程池上使用depends-on 属性,它具有@Async 和@Scheduled 注释.似乎它们从来没有被执行过,我也没有收到上下文初始化错误.我假设带注释的服务 bean 需要首先初始化这些线程池,如果我使用依赖,我会颠倒顺序并使它们不起作用.

I have also tried using the depends-on attribute on the thread pools referring to my service bean which has the @Async and @Scheduled annotations. Seems like they are never executed then and I do not get context initialization errors. I assume the annotated service bean somehow needs these thread pools initialized first and if I use depends-on I reverse the order and make them non-functional.

推荐答案

两种方式:

  1. 让一个 bean 实现 ApplicationListener.onApplicationEvent() 将在上下文之前被调用并且所有 bean 被销毁.

  1. Have a bean implement ApplicationListener<ContextClosedEvent>. onApplicationEvent() will get called before the context and all the beans are destroyed.

有一个bean实现Lifecycle智能生命周期.stop() 将在上下文之前被调用并且所有 bean 都被销毁.

Have a bean implement Lifecycle or SmartLifecycle. stop() will get called before the context and all the beans are destroyed.

无论哪种方式,您都可以在 bean 销毁机制发生之前关闭任务.

Either way you can shut down the task stuff before the bean destroying mechanism takes place.

例如:

@Component
public class ContextClosedHandler implements ApplicationListener<ContextClosedEvent> {
    @Autowired ThreadPoolTaskExecutor executor;
    @Autowired ThreadPoolTaskScheduler scheduler;

    @Override
    public void onApplicationEvent(ContextClosedEvent event) {
        scheduler.shutdown();
        executor.shutdown();
    }       
}

(固定方法签名)

这篇关于如何在 Web 应用程序中的所有其他 bean 被销毁之前关闭 Spring 任务执行程序/调度程序池?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆