1. 程式人生 > 實用技巧 >Spring關閉Tomcat Servlet容器時記憶體洩漏問題解決方案

Spring關閉Tomcat Servlet容器時記憶體洩漏問題解決方案

這篇文章主要介紹了Spring關閉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關閉的時候關閉執行緒

以上就是本文的全部內容,希望對大家的學習有所幫助,也希望大家多多支援碼農教程。