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