溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點(diǎn)擊 登錄注冊 即表示同意《億速云用戶服務(wù)條款》

如何解決Spring關(guān)閉Tomcat Servlet容器時(shí)內(nèi)存泄漏的問題

發(fā)布時(shí)間:2021-07-20 14:04:52 來源:億速云 閱讀:126 作者:小新 欄目:編程語言

這篇文章主要介紹如何解決Spring關(guān)閉Tomcat Servlet容器時(shí)內(nèi)存泄漏的問題,文中介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們一定要看完!

出錯(cuò)信息

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容器關(guān)閉時(shí)發(fā)現(xiàn)Quartz定時(shí)器線程還在執(zhí)行,對其無所適從,不懂怎么辦只能強(qiáng)行關(guān)閉。

解決思路

在關(guān)閉容器時(shí)的contextDestroyed事件里檢測ServletContext里Quartz相關(guān)屬性,找到Bean然后調(diào)用它的方法結(jié)束掉。

解決方法

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("發(fā)現(xiàn)quartz定時(shí)任務(wù)");
           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....");*/
  }
|

關(guān)閉tomcat日志如下:

如何解決Spring關(guān)閉Tomcat Servlet容器時(shí)內(nèi)存泄漏的問題

其他解決方法

Spring配置文件

筆者經(jīng)過實(shí)踐,發(fā)現(xiàn)在spring配置文件里設(shè)置參數(shù)也可以達(dá)到以上效果

<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關(guān)閉的時(shí)候關(guān)閉線程

以上是“如何解決Spring關(guān)閉Tomcat Servlet容器時(shí)內(nèi)存泄漏的問題”這篇文章的所有內(nèi)容,感謝各位的閱讀!希望分享的內(nèi)容對大家有幫助,更多相關(guān)知識(shí),歡迎關(guān)注億速云行業(yè)資訊頻道!

向AI問一下細(xì)節(jié)

免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點(diǎn)不代表本網(wǎng)站立場,如果涉及侵權(quán)請聯(lián)系站長郵箱:is@yisu.com進(jìn)行舉報(bào),并提供相關(guān)證據(jù),一經(jīng)查實(shí),將立刻刪除涉嫌侵權(quán)內(nèi)容。

AI