• Spring整合quartz关闭,关闭Tomcat Servlet容器时内存泄漏


    出错信息

    22-Sep-2017 06:19:51.064 WARNING [main] org.apache.catalina.loader.WebappClassLoaderBase.clearReferencesThreads The web application [license] appears to have started a thread named [org.springframework.scheduling.quartz.SchedulerFactoryBean#0_Worker-1] but has failed to stop it. This is very likely to create a memory leak. Stack trace of thread:
     java.lang.Object.wait(Native Method)
     org.quartz.simpl.SimpleThreadPool$WorkerThread.run(SimpleThreadPool.java:568)

    问题分析:servlet容器关闭时发现Quartz定时器线程还在执行,对其无所适从,不懂怎么办只能强行关闭。

    解决思路,在关闭容器时的contextDestroyed事件里检测ServletContext里Quartz相关属性,找到Bean然后调用它的方法结束掉。

    解决方法:

    import java.sql.Driver;
    import java.sql.DriverManager;
    import java.sql.SQLException;
    import java.util.Enumeration;
    
    import javax.servlet.ServletContextEvent;
    import javax.servlet.ServletContextListener;
    import javax.servlet.ServletRequestEvent;
    import javax.servlet.ServletRequestListener;
    import javax.servlet.annotation.WebListener;
    import javax.servlet.http.HttpSessionEvent;
    import javax.servlet.http.HttpSessionListener;
    
    import org.apache.logging.log4j.web.Log4jWebSupport;
    import org.quartz.impl.StdScheduler;
    import org.slf4j.Logger;
    import org.slf4j.LoggerFactory;
    import org.springframework.web.context.WebApplicationContext;
    import org.springframework.web.context.support.WebApplicationContextUtils;
    
    @WebListener
    public class AppContextListener implements ServletContextListener
    {
    
        public void contextDestroyed(ServletContextEvent event)  {
            logger.info("Destroying Context...");
         
          try {    
              WebApplicationContext context = (WebApplicationContext) event.getServletContext().getAttribute(
                  WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE);
              
              Enumeration<String> attributes = event.getServletContext().getAttributeNames();
              while(attributes.hasMoreElements())
              {
              String attr = attributes.nextElement();
              Object prop = event.getServletContext().getAttribute(attr);
              logger.info("attribute.name: {},class:{}, value:{}",attr,prop.getClass().getName(),prop);
              }
              
              String[] beanNames = context.getBeanDefinitionNames();
              
              for(String beanName:beanNames)
              {
              Object bean = context.getBean(beanName);
              logger.info("found bean attribute in ServletContext,name:{},class:{},value:{}",
                      beanName,bean.getClass().getName(),bean);                      
              if(beanName.contains("quartz")&&beanName.contains("Scheduler")){
                  StdScheduler scheduler = (StdScheduler)context.getBean("org.springframework.scheduling.quartz.SchedulerFactoryBean#0");
                  logger.info("发现quartz定时任务");
                         logger.info("beanName:{},className:{}",scheduler,scheduler.getClass().getName());
                  if(scheduler.isStarted())
                  {
                  logger.info("Quartz:waiting for job complete...");
                  scheduler.shutdown(true);
                  logger.info("Quartz:all threads are complete and exited...");
                  }
              }
              }
              
          } catch (Exception e) {
              logger.error("Error Destroying Context", e);
          }
        }
    
        //https://stackoverflow.com/questions/23936162/register-shutdownhook-in-web-application
        public void contextInitialized(ServletContextEvent event)  { 
              //ServletContext context = event.getServletContext();        
              //System.setProperty("rootPath", context.getRealPath("/"));
              //LoggerContext ctx = (LoggerContext) LogManager.getContext(false);
                  //ctx.reconfigure();
              /*logger.info("global setting,rootPath:{}",rootPath);
               logger.info("deployed on architecture:{},operation System:{},version:{}",
                       System.getProperty("os.arch"), System.getProperty("os.name"),
                       System.getProperty("os.version"));
               Debugger.dump();
               logger.info("app startup completed....");*/
        }
    |

    关闭tomcat日志如下:

     其他解决方法:Spring配置文件

    笔者经过实践,发现在spring配置文件里设置参数也可以达到以上效果

      <bean class="org.springframework.scheduling.quartz.SchedulerFactoryBean">
            <property name="triggers">
                <list>
                    <ref bean="simpleTrigger" />
                    <ref bean="cronTrigger" />
                    <ref bean="secondCronTrigger"/>
                </list>
            </property>
            <property name="waitForJobsToCompleteOnShutdown" value="true"/>  
        </bean>
    <property name="waitForJobsToCompleteOnShutdown" value="true"/>可以在web关闭的时候关闭线程
  • 相关阅读:
    Linux-文件编程
    Linux-编程基础
    Linux-系统管理
    Linux-命令
    图解HTTP-笔记
    微信小程序发送红包功能。填坑记录
    PHP中使用raw格式发送POST请求
    论一个PHP项目上线的注意点
    PHP CURL 模拟form表单上传遇到的小坑
    使用php的curl函数post返回值为301永久迁移的问题。(301 Moved Permanently)
  • 原文地址:https://www.cnblogs.com/passedbylove/p/7580477.html
Copyright © 2020-2023  润新知