register the mysql,解决 registered the JDBC driver [com.mysql.cj.jdbc.Driver] but failed to unregister...

Springboot在tomcat Undeploying,或者容器中关闭时老是提示如下警告,虽然不会影响程序的运行,但是还是想去掉这些不必要的异常:

xxx 警告 [http-nio-8080-exec-56] org.apache.catalina.loader.WebappClassLoaderBase.clearReferencesJdbc The web application [gasbj] registered the JDBC driver [com.alibaba.druid.proxy.DruidDriver] but failed to unregister it when the web application was stopped. To prevent a memory leak, the JDBC Driver has been forcibly unregistered.

xxx 警告 [http-nio-8080-exec-56] org.apache.catalina.loader.WebappClassLoaderBase.clearReferencesJdbc The web application [gasbj] registered the JDBC driver [com.mysql.cj.jdbc.Driver] but failed to unregister it when the web application was stopped. To prevent a memory leak, the JDBC Driver has been forcibly unregistered.

xxx 警告 [http-nio-8080-exec-56] org.apache.catalina.loader.WebappClassLoaderBase.clearReferencesThreads The web application [gasbj] appears to have started a thread named [mysql-cj-abandoned-connection-cleanup] but has failed to stop it. This is very likely to create a memory leak. Stack trace of thread:

java.lang.Object.wait(Native Method)

java.lang.ref.ReferenceQueue.remove(Unknown Source)

com.mysql.cj.jdbc.AbandonedConnectionCleanupThread.run(AbandonedConnectionCleanupThread.java:85)

java.util.concurrent.ThreadPoolExecutor.runWorker(Unknown Source)

java.util.concurrent.ThreadPoolExecutor$Worker.run(Unknown Source)

java.lang.Thread.run(Unknown Source)

xxx 信息 [mysql-cj-abandoned-connection-cleanup] org.apache.catalina.loader.WebappClassLoaderBase.checkStateForResourceLoading Illegal access: this web application instance has been stopped already. Could not load []. The following stack trace is thrown for debugging purposes as well as to attempt to terminate the thread which caused the illegal access.

java.lang.IllegalStateException: Illegal access: this web application instance has been stopped already. Could not load []. The following stack trace is thrown for debugging purposes as well as to attempt to terminate the thread which caused the illegal access.

at org.apache.catalina.loader.WebappClassLoaderBase.checkStateForResourceLoading(WebappClassLoaderBase.java:1348)

at org.apache.catalina.loader.WebappClassLoaderBase.getResource(WebappClassLoaderBase.java:1007)

at com.mysql.cj.jdbc.AbandonedConnectionCleanupThread.checkThreadContextClassLoader(AbandonedConnectionCleanupThread.java:117)

at com.mysql.cj.jdbc.AbandonedConnectionCleanupThread.run(AbandonedConnectionCleanupThread.java:84)

at java.util.concurrent.ThreadPoolExecutor.runWorker(Unknown Source)

at java.util.concurrent.ThreadPoolExecutor$Worker.run(Unknown Source)

at java.lang.Thread.run(Unknown Source)

发生这种异常的原因有两个:

一是Tomcat在 6.0.24 后加入了一个 memory leak detection 检查机制,当我们程序中引入了JDBC 4.0 驱动时会自动注册到Tomcat容器中,但是却没有提供自动销毁机制。

二是我们Mysql驱动中自带的AbandonedConnectionCleanupThread类,会在我们加载jdbc驱动时启动一个newSingleThreadExecutor的线程池,这个也不会自动释放。

解决方式如下(注册一个ServletContextListener,注意使用@ServletComponentScan来扫描):

package com.iwhere.gasbj.config.listener;

import lombok.extern.slf4j.Slf4j;

import javax.servlet.ServletContextEvent;

import javax.servlet.ServletContextListener;

import javax.servlet.annotation.WebListener;

import java.lang.reflect.InvocationTargetException;

import java.lang.reflect.Method;

import java.sql.Driver;

import java.sql.DriverManager;

import java.sql.SQLException;

import java.util.Enumeration;

@WebListener

@Slf4j

public class JdbcUnregisterListener implements ServletContextListener {

@Override

public void contextDestroyed(ServletContextEvent sce) {

try {

log.info("Calling MySQL AbandonedConnectionCleanupThread checkedShutdown");

// Or com.mysql.jdbc.AbandonedConnectionCleanupThread

Class cls = Class.forName("com.mysql.cj.jdbc.AbandonedConnectionCleanupThread");

Method method = cls.getMethod("checkedShutdown");

method.invoke(null);

} catch (ClassNotFoundException | NoSuchMethodException | IllegalAccessException | InvocationTargetException e) {

log.error("Cannot call MySQL AbandonedConnectionCleanupThread.checkedShutdown!", e);

}

// Now deregister JDBC drivers in this context's ClassLoader:

// Get the webapp's ClassLoader

ClassLoader cl = Thread.currentThread().getContextClassLoader();

// Loop through all drivers

Enumeration drivers = DriverManager.getDrivers();

while (drivers.hasMoreElements()) {

Driver driver = drivers.nextElement();

if (driver.getClass().getClassLoader() == cl) {

// This driver was registered by the webapp's ClassLoader, so deregister it:

try {

log.info("Deregistering JDBC driver {}", driver);

DriverManager.deregisterDriver(driver);

} catch (SQLException ex) {

log.error("Error deregistering JDBC driver {}", driver, ex);

}

} else {

// driver was not registered by the webapp's ClassLoader and may be in use elsewhere

log.trace("Not deregistering JDBC driver {} as it does not belong to this webapp's ClassLoader", driver);

}

}

}

}

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值