某次更新,将项目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"); } }