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