Tomcat报registered the JDBC driver [Oracle.jdbc.driver.OracleDriver] but failed to unregister it

     很久没写博客了,项目中用的是pooxl.0.9.1连接池,连接池自带相应的bug已修复

tomcat运行或者reaload之后,tomcat运行出现 如下异常:

严重: The web application [/XXX] registered the JDBC driver [oracle.jdbc.driver.OracleDriver] but failed to unregister it when the web application was stopped. To prevent a memory leak, the JDBC Driver has been forcibly unregistered.

The web application [/XXX] appears to have started a thread named [HouseKeeper] but has failed to stop it. This is very likely to create a memory leak.

     刚开始怀疑是tomcat连接池,资源在关闭的时候没有释放,导致内存泄露,tomcat6.0.2X之后,推出一个防止内存泄漏的监听,目录为/conf/server.xml 中

 <Listener className="org.apache.catalina.core.JreMemoryLeakPreventionListener" />把他注释掉,也没好用,还是同样出这种问题,由于是在生产环境也不能随意更换tomcat版本,所以继续想别的办法,后来想到既然jdbc没有释放,何不在关闭tomcat 服务的时候,手动来关闭呢,于是想到了增加一个ServletContextListener监听:首先在web.xml中加入一个监听:

<listener>
    	<listener-class>
            com.xx.dbprovider.DBPooxDriverListener
        </listener-class>
</listener> 
 

然后让DBPooxDriverListener实现ServletContextListener接口,在contextDestroyed对所有的驱动进行关闭

public class DBPooxDriverListener implements ServletContextListener {
	
	private ServletContextEvent context=null;
	@Override
	public void contextDestroyed(ServletContextEvent destoryContext) {
		// TODO Auto-generated method stub
		 Enumeration<Driver> drivers = DriverManager.getDrivers();
	        while (drivers.hasMoreElements()) {
	            Driver driver = drivers.nextElement();
	            try {
	                DriverManager.deregisterDriver(driver);
	            } catch (SQLException e) {
	            	e.printStackTrace();
	            }
	        }
	     System.out.println("关闭所有数据库连接");
	     //destroyThreads();
	     
	}

	@Override
	public void contextInitialized(ServletContextEvent context) {
		// TODO Auto-generated method stub
		context=this.context;
	}
	
	/**
	 * 销毁未正常关闭的线程
	 */
	private void destroyThreads(){  
	      final Set<Thread> threads = Thread.getAllStackTraces().keySet();    
	      for (Thread thread : threads) {                
		      if(thread.getName().equals("HouseKeeper")){  
		           synchronized (this) {    
		             try {    
		                thread.stop();    
		                  return;  
		             } catch (Exception e) {
		            	 e.printStackTrace();
		             }    
		           }    
		    }    
	      }
	}  
	
}
 

然后发布,重启,关闭,在重启,这样保证手动把未正常关闭jdbc连接,关闭掉,可是运行了几天,又出现了如下错误:

The web application [/XXX] appears to have started a thread named [HouseKeeper] but has failed to stop it. This is very likely to create a memory leak.

这次不报jdbc相关连接未关闭,后来又加上了,如上注释掉的 //destroyThreads();方法,在关闭tomcat的时候,同时关闭掉这个线程,就好了,用jdk自带的工具jvisualvm.exe,在jdk安装目录找到即可,不过需要在tomcat的bin/catalina.bat 配置一下:

set JAVA_OPTS=-Dcom.sun.management.jmxremote -Dcom.sun.management.jmxremote.port=9080 -Dcom.sun.management.jmxremote.authenticate=false -    Dcom.sun.management.jmxremote.ssl=false
 

然后tomcat在运行状态,直接双击jvisualvm.exe文件,既可以打开,可以对tomat做相应的监控。


如果如上办法还是不能解决的话,可以尝试做一个守护程序,当tomcat挂掉,或者宕机重启tomcat,不过此方法,不是最好的办法,在这简单说下这个方法,做一个简单页面,然后用URLConnection 定时去连接tomcat服务器,如果返回有内容,说明tomcat正常,如果返回失败,说明tomcat存在异常,需要用到java.lang.Runtime.getRuntime().exec(tomcatRoot+"bin//shutdown.bat"),有的用net start tomcat6 命令,需要把服务注册到系统服务里,操作起来感觉挺麻烦的,直接这样就可以,也不同注册服务,然后开启一个线程,设定一个定时去连接tomcat,一旦发生异常,重启就可以,下面是代码,不过此代码有这样的一个弊端,必须要把tomcat启动后的等待时间设置稍微长一些,否则会导致tomcat连续开启多个tomcat,下面是代码,大家可以交流探讨下:

/**
 * tomcat 服务监听守护线程
 * @author lt
 *
 */
public class TomcatMonitor implements Runnable {
	
    String start=""; //系统命令 启动  
    String stop=""; //系统命令 关闭  
    String testHttp="";  //测试连接地址  
    String tomcatRoot="";  //tomcat根目录  
    int testIntervalTime=1;//测试连接间隔时间,单位为秒  
    int waitIntervalTime=2; //等待测试间隔时间,单位为秒  
    int testTotalCount=5; //测试连接总次数  
      
    Thread thread=null;  
    
    public TomcatMonitor(){ 
    	
    	ResourceBundle config= ResourceBundle.getBundle("config");
         try {  
            stop=config.getString("stop");  
            start=config.getString("start");  
            testHttp=config.getString("testHttp");  
            tomcatRoot=config.getString("tomcatRoot");  
            testIntervalTime=Integer.parseInt(config.getString("testIntervalTime"));  
            waitIntervalTime=Integer.parseInt(config.getString("waitIntervalTime"));  
            testTotalCount=Integer.parseInt(config.getString("testTotalCount"));             
        } catch (Exception e) {  
                    e.printStackTrace();  
        }  
              
        System.out.println("*******************初始化成功!*******************");  
           
          
        thread=new Thread(this);  
        thread.start();       
    } 
	
	public void run() {
		  System.out.println("正在监控中...");     
	      int testCount=0;  
		  while (true) {
				testCount=0;  
	            testCount++;              
	            boolean isrun=checkStatus();  
	            System.out.println("正在启动测试连接,尝试连接次数为:"+testCount+",结果为:"+(isrun==false?"失败.":"成功! ")+ getCurrentTime());                 
	            
	            //检测状态
	            while (!isrun) {
	            	if(testCount>=testTotalCount)break;  
					try {
						thread.sleep(testIntervalTime*1000);
					} catch (InterruptedException e) {
						// TODO Auto-generated catch block
						e.printStackTrace();
					}
					 testCount++;  
	                 System.out.println("正在启动测试连接,尝试连接次数为:"+testCount+",结果为:"+(isrun==false?"失败.":"成功! ")+getCurrentTime());                 
	                 isrun=checkStatus();
				}
	            
	            //先关闭,后启动服务
	            while (!isrun) {
					try {
						System.out.println("正在执行关闭......");
						Runtime.getRuntime().exec(tomcatRoot+"bin//shutdown.bat");//先执行关闭
						thread.sleep(8000);
						System.out.println("正在重新启动......");
						Runtime.getRuntime().exec(tomcatRoot+"bin//startup.bat");//启动
						thread.sleep(waitIntervalTime*1000); 
						System.out.println("重启tomcat成功");
						isrun=checkStatus();//重启后,再次连接看是否正常  
					} catch (Exception e) {
						// TODO Auto-generated catch block
						e.printStackTrace();
						System.out.println("重启tomcat异常,请查看先关错误信息");  
					}
				}
	            
	            try {  
	                thread.sleep(waitIntervalTime*1000);  
	            } catch (InterruptedException e) {  
	                e.printStackTrace();  
	            }  
	              
		  }
		
	}
	
	/**
	 * 检查服务器状态
	 * @return true:运行正常 ;false:服务器发生异常
	 */
	public boolean checkStatus() {
		URL url=null;
		InputStreamReader in=null;
		try {
			url=new URL(testHttp);
			URLConnection urlConn=url.openConnection();
			urlConn.setConnectTimeout(15000);
			urlConn.setReadTimeout(4000);
			in=new InputStreamReader( urlConn.getInputStream());
			BufferedReader reader = new BufferedReader(in);//实例化输入流,并获取网页代码  
            String s;                                         
            while ((s = reader.readLine()) != null) { 
            	System.out.println("返回值:"+s);
               return true;     
            }             
		} catch (IOException e) {
			// TODO Auto-generated catch block
//			e.printStackTrace();
			System.out.println(e.getMessage());
			return false;
		}finally {
			if (in!=null) {
				try {
					in.close();
				} catch (IOException e) {
					// TODO Auto-generated catch block
					e.printStackTrace();
					System.out.println("关闭文件流失败****");
				}
			}
		}
		return false;
	}
	
	public String getCurrentTime() {
		SimpleDateFormat sdf=new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
		return sdf.format(new Date());
	}
	
	 public static void main(String[] args) throws Exception{  
	        TomcatMonitor tm=new TomcatMonitor();
//	        tm.run();
//		 String tomcatRoot="D:/apache-tomcat-6.0.35restart/";
//		 Process p= java.lang.Runtime.getRuntime().exec(tomcatRoot+"bin//startup.bat");//启动
//		 java.io.BufferedReader in = new java.io.BufferedReader(new java.io.InputStreamReader(p.getInputStream()));
		
	    /* String tomcatRoot="D:/apache-tomcat-6.0.35restart/";
		 Process p= java.lang.Runtime.getRuntime().exec(tomcatRoot+"bin//shutdown.bat");//启动
		 java.io.BufferedReader in = new java.io.BufferedReader(new java.io.InputStreamReader(p.getInputStream()));
		 
		 String s;
		   boolean restart = false;
		   String t = "Server startup in";
		   while ((s = in.readLine()) != null) {
		    System.out.println(s);
		    if (s.indexOf(t) != -1) {
		     restart = true;
		     break;
		    }
		   }*/
	 }  
}
 

下面是配置文件:

#测试连接总次数  
testTotalCount=3
  
#连接失败时,再次检测时间间隔,单位为秒  
testIntervalTime=3
  
#连接超时时间,即多少秒tomcat没响应视为宕机,单位为秒  
connectionTimeout=15
  
#tomcat启动时间,防止在tomcat尚未启动完成的时候,程序又去检验tomcat状态,造成尚未启动完成又重新启动,单位为秒  
tomcatStartTime=600
  
#测试连接地址  
testHttp=http://127.0.0.1:9080/SpringMvcMQ/login
#testHttp=http://192.168.31.156:8080/nhip/enterapp.do?method=begin&name=/ESBManager&welcome=/ESBManager/pages/index.jsp


#tomcat根目录
tomcatRoot=D:/apache-tomcat-6.0.35restart/
  
#正常情况下,每次检测间隔时间,单位为秒  
waitIntervalTime=90
 放到web.xml做监听:

<listener>
    	<listener-class>com.neusoft.nhip.monitor.TomcatMonitorListener</listener-class>
  </listener>
  
  <welcome-file-list>
    <welcome-file>index.html</welcome-file>
  </welcome-file-list>
  
tomcat服务一启动就会执行该守护线程,同时更加明了的看到tomcat的运行状态




  • 2
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值