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