SSM框架 Tomcat 停止时 JAVA进程未停止 的解决方法

在使用SSM框架,tomcat发布项目,结束项目时,SSM框架结束时报错如下:
报错信息

这会导致Tomcat 服务器停止后Java进程尚未停止, 继续占用内存, 必须通过 类似 kill -9 之类的命令去杀死java进程.

这是由于在服务器停止时有些线程尚未销毁所引起的, 如ThreadLocal; Scheduler 启动的线程; JDBC driver等.

解决办法:
自定义ContextLoaderListener,在项目结束时关闭他们:

/**
 * 自定义的ContestLoaderListener
 * 监听servletContext创建和消亡,即web应用的开始和结束时执行
 * 本类继承自SpringMVC的ContextLoaderListener
 * 在执行本类方法前首先执行父类方法
 * <p>
 * 需要配置本类在 web.xml 文件中:
 * <listener>
 * <listener-class>com.qinghe.MyContextLoaderListener</listener-class>
 * </listener>
 * <p>
 * auther:XingTL
 * date:2020/6/20 17:46
 */
public class MyContextLoaderListener extends ContextLoaderListener {
    private static final Logger logger = (ch.qos.logback.classic.Logger) LoggerFactory.getLogger("com.qinghe.MyContextLoaderListener");

    /**
     * 当Servlet 容器启动Web 应用时调用该方法。
     * 在调用完该方法之后,容器再对Filter 初始化,
     * 并且对那些在Web 应用启动时就需要被初始化的Servlet 进行初始化。
     *
     * @param sce servletContext 初始化事件 即web应用开始
     */
    @Override
    public void contextInitialized(ServletContextEvent sce) {
        super.contextInitialized(sce);
    }

    //实现其中的销毁函数
    @Override
    public void contextDestroyed(ServletContextEvent sce) {
        super.contextDestroyed(sce);
        //销毁线程等
        destroyJDBCDrivers();
        destroySpecifyThreads();
    }

    private void destroySpecifyThreads() {
        final Set<Thread> threads = Thread.getAllStackTraces().keySet();
        for (Thread thread : threads) {
            if (needManualDestroy(thread)) {
                synchronized (this) {
                    try {
                        thread.stop();
                        logger.debug(String.format("Destroy  %s successful", thread));
                    } catch (Exception e) {
                        logger.warn(String.format("Destroy %s error", thread), e);
                    }
                }
            }
        }
    }
	//该数组中即为报错的未结束的线程名
    private final String[] MANUAL_DESTROY_THREAD_IDENTIFIERS = {
            "Timer-0",
            "com.mchange.v2.async.ThreadPoolAsynchronousRunner$PoolThread-#0",
            "com.mchange.v2.async.ThreadPoolAsynchronousRunner$PoolThread-#1",
            "com.mchange.v2.async.ThreadPoolAsynchronousRunner$PoolThread-#2",
    };

    private boolean needManualDestroy(Thread thread) {
        final String threadName = thread.getName();
        for (String manualDestroyThreadIdentifier : MANUAL_DESTROY_THREAD_IDENTIFIERS) {
            if (threadName.contains(manualDestroyThreadIdentifier)) {
                return true;
            }
        }
        return false;
    }

    private void destroyJDBCDrivers() {
        final Enumeration<Driver> drivers = DriverManager.getDrivers();
        Driver driver;
        while (drivers.hasMoreElements()) {
            driver = drivers.nextElement();
            try {
                DriverManager.deregisterDriver(driver);
                logger.debug(String.format("Deregister JDBC driver %s successful", driver));
            } catch (SQLException e) {
                logger.warn(String.format("Deregister JDBC driver %s error", driver), e);
            }
        }
    }
}

问题解决

本文参考:https://blog.csdn.net/monkeyking1987/article/details/9182201

posted @ 2020-07-01 01:14  xtLLL  阅读(179)  评论(0编辑  收藏  举报