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

来源:互联网 发布:zynq linux 编辑:程序博客网 时间:2024/05/16 07:31

     很久没写博客了,项目中用的是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;@Overridepublic 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();     }@Overridepublic void contextInitialized(ServletContextEvent context) {// TODO Auto-generated method stubcontext=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 blocke.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 blocke.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 blocke.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的运行状态




0 0
原创粉丝点击