记一次Quartz定时任务导致的系统崩溃Debug过程

公司一个Spring+Hibernate架构的后台管理项目部署到远程服务器的tomcat上,tomcat里reloadable设置为true。

某次更新,将项目class文件替换后,系统自动reload,正常运行。大概一小时后,有人反映说系统无法访问了。后台一查,tomcat已经停止服务了。

查询log日志,未见相关报错。遂找到catalina.out文件,发现系统在重启时有十来条类似如下所示的警告信息:
The web application [/project] appears to have started a thread named [SchedulerFactoryBean-Worker-1] but has faild to stop it. This is very likely to create a memory leak。大意就是某个线程在系统关闭的时候没有被停止掉,可能导致内存泄漏。

看到SchedulerFactoryBean,了解到问题应该出在Quartz定时调度上面。网上查询相关资料,得出出现此问题的原因大概是:系统在关闭时没有给Quartz时间来停止它所创建的定时任务,导致线程未被停止系统便已经关闭了。

解法如下:配置QuartzContextListener实现ServletContextListener,并在ContextDestroyed时执行SchedulerFactoryBean的shutdown方法。以下是代码:

(别忘了在web.xml里面配置上QuartzContextListener哦)

import javax.servlet.ServletContextEvent;
import javax.servlet.ServletContextListener;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.web.context.WebApplicationContext;

public class QuartzContextListener implements ServletContextListener{

	@Override
	public void contextDestroyed(ServletContextEvent arg0) {
		WebApplicationContext webApplicationContext = (WebApplicationContext) arg0  
				.getServletContext()  
				.getAttribute(  
						WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE);  
		org.quartz.impl.StdScheduler schedulerFactoryBean = (org.quartz.impl.StdScheduler) webApplicationContext  
				.getBean("schedulerFactoryBean");//配置文件里配置的quartz的beanId 
		if(schedulerFactoryBean != null) {  
			schedulerFactoryBean.shutdown();  
		}  
		try {  
			Thread.sleep(5000);//主线程暂停一定时间让quartz schedular执行shutdown  
		} catch (InterruptedException e) {  
			e.printStackTrace();  
		} 
	}

	@Override
	public void contextInitialized(ServletContextEvent arg0) {
		Logger logger = LoggerFactory.getLogger(getClass());
		logger.info("QuartzContextListener is initializing");
	}

}


猜你喜欢

转载自leozam.iteye.com/blog/2360665