在Spring Web应用程序中,我有几个DAO和服务层bean。一个服务层bean带有注释的@Async / @Scheduled方法。这些方法取决于其他(自动装配)的bean。我已经在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已被销毁,但某些工作任务线程仍在执行,并且由于其依赖关系被销毁而失败。
JIRA问题可能与此有关:SPR-5387
我的问题是:有没有办法告诉Spring最后初始化任务执行者/调度程序bean,还是有办法告诉Spring首先销毁它们?
我的理解是破坏是以相反的顺序发生的。因此,最后初始化的bean将首先被销毁。如果线程池bean首先被销毁,则所有当前正在执行的任务将完成,并且仍可以访问相关的bean。
我还尝试在引用我的具有@Async和@Scheduled批注的服务bean的线程池上使用depends-on属性。好像它们从未执行过,并且我没有遇到上下文初始化错误。我假设带注释的服务bean某种程度上需要首先初始化这些线程池,如果我使用依赖关系,我会颠倒顺序并使它们不起作用。
两种方式:
有一个豆子工具ApplicationListener。 onApplicationEvent()将在上下文和所有bean被销毁之前被调用。
有一个bean实现Lifecycle或SmartLifecycle。 stop()将在上下文和所有bean被销毁之前被调用。
无论哪种方式,你都可以在Bean销毁机制发生之前关闭任务。
例如:
@Component public class ContextClosedHandler implements ApplicationListener<ContextClosedEvent> { @Autowired ThreadPoolTaskExecutor executor; @Autowired ThreadPoolTaskScheduler scheduler; @Override public void onApplicationEvent(ContextClosedEvent event) { scheduler.shutdown(); executor.shutdown(); } }