我有一个在Tomcat 9上运行的程序。
当我重新启动这个问题时,它显示了上面的警告:
05-Feb-2021 09:48:34.211 WARNING [Thread-5] org.apache.catalina.loader.WebappClassLoaderBase.clearReferencesThreads The web application [AWSApps] 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:
org.apache.catalina.loader.WebappClassLoaderBase.trackLastModified(WebappClassLoaderBase.java:963)
org.apache.catalina.loader.WebappClassLoaderBase.findResource(WebappClassLoaderBase.java:941)
org.apache.catalina.loader.WebappClassLoaderBase.getResource(WebappClassLoaderBase.java:1057)
com.mysql.cj.jdbc.AbandonedConnectionCleanupThread.checkThreadContextClassLoader(AbandonedConnectionCleanupThread.java:117)
com.mysql.cj.jdbc.AbandonedConnectionCleanupThread.run(AbandonedConnectionCleanupThread.java:84)
java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149)
java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624)
java.lang.Thread.run(Thread.java:748)Tomcat版本: Tomcat 9 JVM : java-8-openjdk-amd64 64 Mysql驱动程序:mysql-连接器-java-8.0.20
server.xml
driverClassName="com.mysql.jdbc.Driver"我试着把server.xml改成
com.mysql.cj.jdbc.Driver但在Catalina.out中仍然存在警告。
有解决这个问题的指南吗?
谢谢。
发布于 2021-02-05 07:23:57
如果web应用程序在MySQL文件夹中有WEB-INF/lib JDBC驱动程序的副本,那么Tomcat中使用的特殊类加载器的委托规则将选择web应用程序的驱动程序副本,而不是全局驱动程序副本。
这将在引导类加载器中在应用程序的类加载器上创建两个引用:
DriverManager (在引导类加载程序中),ContextClassLoader设置为webapp类加载器。这两个引用都可以创建内存泄漏。
备注:即使不直接使用DriverManager,但某些数据库池库(最终将使用DriverManager )或在<Context>中定义JNDI <Resource>,也会发生JNDI。只有在<Resource>中定义的<GlobalNamingResources>的情况不受影响。
要解决这个问题,您可以:
WEB-INF/lib目录中删除数据库驱动程序,DriverManager.deregister (例如在ServletContextListener中)来逆转这些更改:public class JdbcDriverListener implements ServletContextListener {
/**
* Deregisters the JDBC drivers distributed with the application.
*/
@Override
public void contextDestroyed(ServletContextEvent event) {
final ClassLoader cl = event.getServletContext().getClassLoader();
final Enumeration<Driver> drivers = DriverManager.getDrivers();
while (drivers.hasMoreElements()) {
final Driver driver = drivers.nextElement();
// We deregister only the classes loaded by this application's classloader
if (driver.getClass().getClassLoader() == cl) {
try {
DriverManager.deregisterDriver(driver);
} catch (SQLException e) {
event.getServletContext().log("JDBC Driver deregistration failure.", e);
}
}
}
}
/**
* Registers the JDBC drivers distributed with the application.
*/
@Override
public void contextInitialized(ServletContextEvent event) {
Iterator<@NonNull Driver> driversIterator = ServiceLoader.load(Driver.class).iterator();
while (driversIterator.hasNext()) {
try {
// Instantiates the driver
driversIterator.next();
} catch (Throwable t) {
event.getServletContext().log("JDBC Driver registration failure.", t);
}
}
}
}编辑:,我将注释中的信息合并到答案中。
https://stackoverflow.com/questions/66056707
复制相似问题