使用"Tomcat+Spring+Quartz"解决方案,在关闭Tomcat时出现如图1所示错误信息:
图1
这里使用的Tomcat版本为6.2.32,Spring版本为3.2.3,Quartz版本为1.8.6
在"Tomcat+Spring+Quartz"的解决方案中,Tomcat在运行的时候,Spring中配置的Quartz SchedulerFactoryBean会创建多个工作线程。在Tomcat关闭的时候,检测到这些线程没有得到及时的销毁,因而出现如图1的错误。
二、解决方案
Tomcat关闭的时候,会去销毁Spring实例。根据Spring的生命周期机制,在销毁Spring实例的过程中,会去处理Spring中配置的Bean实例的销毁事宜。只要Spring中配置的Bean实例符合以下图2中的任意一个条件
图2
<bean id="startQuartz" lazy-init="false" autowire="no" class="org.springframework.scheduling.quartz.SchedulerFactoryBean"> <property name="triggers"> <list> <ref bean="doTime"/> </list> </property> </bean>查看org.springframework.scheduling.quartz.SchedulerFactoryBean的源代码,发现它继承org.springframework.beans.factory.DisposableBean接口,满足图2中的条件。因而在Spring实例的销毁过程中,SchedulerFactoryBean实例的destroy()方法会被自动调用。
package com.dslztx.utils; import org.quartz.SchedulerException; import org.springframework.scheduling.quartz.SchedulerFactoryBean; public class SchedulerFactoryBeanWithShutdownDelay extends SchedulerFactoryBean { @Override public void destroy() throws SchedulerException { super.destroy(); try { Thread.sleep(1000); } catch (InterruptedException e) { throw new RuntimeException(e); } } }相应在Spring中的配置片段如下:
<bean id="startQuartz" lazy-init="false" autowire="no" class="com.dslztx.utils.SchedulerFactoryBeanWithShutdownDelay"> <property name="triggers"> <list> <ref bean="doTime"/> </list> </property> </bean>
三、其他
1、由于这些Quartz SchedulerFactoryBean创建的线程最后能够得以关闭,因此Tomcat进程也能被正常关闭,在有些情形中,Tomcat进程内的线程不能得以关闭,那么Tomcat进程也不能被正常关闭,只能通过kill命令,强行杀死进程。
2、这个问题已经在Quartz 2.1上修复
参考文献:
[1]http://forums.terracotta.org/forums/posts/list/3479.page