解决:IDEA 重新部署 Tomcat 服务报异常

一. 重新部署,发生异常,Tomcat停止

背景条件

  • 使用tomcat版本:apache-tomcat-8.5.91

  • 使用连接池版本:

    <dependency>
                <groupId>com.alibaba</groupId>
                <artifactId>druid</artifactId>
                <version>1.2.15</version>
    </dependency>
    

问题

  1. 在IDEA进行tomcat部署,然后访问web数据,在进行重新部署抛异常:
    [mysql-cj-abandoned-connection-cleanup] org.apache.catalina.loader.WebappClassLoaderBase.checkStateForResourceLoading 非法访问:此Web应用程序实例已停止。无法加载[]。为了调试以及终止导致非法访问的线程,将抛出以下堆栈跟踪。

  2. 解决办法:①在项目中新建一个名为ContextFinalizer​​的监听类,具体代码如下:

    package com.panziye.listener;
    import com.mysql.cj.jdbc.AbandonedConnectionCleanupThread;
     
    import javax.servlet.ServletContextEvent;
    import javax.servlet.ServletContextListener;
    import java.sql.Driver;
    import java.sql.DriverManager;
    import java.sql.SQLException;
    import java.util.Enumeration;
     
    @WebListener
    public class ContextFinalizer implements ServletContextListener{
     
        public void contextInitialized(ServletContextEvent sce) {}
     
        public void contextDestroyed(ServletContextEvent sce) {
            Enumeration<Driver> drivers = DriverManager.getDrivers();
            Driver d = null;
            while (drivers.hasMoreElements()) {
                try {
                    d = drivers.nextElement();
                    DriverManager.deregisterDriver(d);
                } catch (SQLException ex) {
                }
            }
            try {
                // 注意:mysql8版本的jar好像shutdown方法私有了,只能调用checkedShutdown或uncheckedShutdown
                AbandonedConnectionCleanupThread.checkedShutdown();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
     }
    
  3. @WebListener​​这个注解相当于在web.xml​​配置如下内容:

    <listener>
              <listener-class> com.panziye.listener.ContextFinalizer </listener-class>
    </listener>
    
  4. 成功解决该异常

二. 内存泄露

承接上面

在IDEA中tomcat重新部署,报内存泄露危险:

Web应用程序[pro05]似乎启动了一个名为[Druid-ConnectionPool-Destroy-257280247]的线程,但未能停止它。这很可能会造成内存泄漏。线程的堆栈跟踪:

原因分析

  1. 在进行tomcat重新部署的情况下,dataSource​ 未能及时关闭释放资源。
  2. 在进行主程序停止时,未能及时停止它,造成系统资源浪费。

解决过程

  1. 解决思路:进行连接池的关闭操作。

  2. 发现dataSource​​ 对象中并没有,close()方法。

  3. 查看 阿里 Druid 源代码,发现其 DruidDataSource​​ 是有 close() 方法的。

    • DruidDataSourceFactory.java​​ 文件中,有以下源码:

      @SuppressWarnings("rawtypes")
          public static DataSource createDataSource(Map properties) throws Exception {
      	// 进行了向上转型
              DruidDataSource dataSource = new DruidDataSource();
              config(dataSource, properties);
              return dataSource;
          }
      
    • DruidDataSource.java​​ 的源代码:
      images

    • 得出dataSource的运行时对象是可以进行 close() 方法。

  4. 在监听器中添加以下源码:

    package com.panziye.listener;
    import com.mysql.cj.jdbc.AbandonedConnectionCleanupThread;
     
    import javax.servlet.ServletContextEvent;
    import javax.servlet.ServletContextListener;
    import java.sql.Driver;
    import java.sql.DriverManager;
    import java.sql.SQLException;
    import java.util.Enumeration;
     
    @WebListener
    public class ContextFinalizer implements ServletContextListener{
     
        public void contextInitialized(ServletContextEvent sce) {}
     
        public void contextDestroyed(ServletContextEvent sce) {
            Enumeration<Driver> drivers = DriverManager.getDrivers();
            Driver d = null;
            while (drivers.hasMoreElements()) {
                try {
                    d = drivers.nextElement();
                    DriverManager.deregisterDriver(d);
                } catch (SQLException ex) {
                }
            }
            try {
                System.out.println("===============进行连接池关闭释放==========================");
                /*
    		JDBCUtils中的close()方法,其中 dataSource 是 JDBCUtils的静态属性
    		public static void closeDruidDataSource(){
    			DruidDataSource druidDataSource = (DruidDataSource) dataSource;
    			druidDataSource.close();
    		}
    	    */
    	    JDBCUtils.closeDruidDataSource();
                // 注意:mysql8版本的jar好像shutdown方法私有了,只能调用checkedShutdown或uncheckedShutdown
                AbandonedConnectionCleanupThread.checkedShutdown();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
     }
    
  5. 进行重新部署,问题完美解决:
    images

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值