Java 如何在关闭/重新部署时关闭HikariCP JNDI数据源

Java 如何在关闭/重新部署时关闭HikariCP JNDI数据源,java,spring,jetty,jndi,hikaricp,Java,Spring,Jetty,Jndi,Hikaricp,我在Spring和Jetty 9中使用HikariCP 2.3.3,并试图解决这样一个事实:当我热部署一个新的war文件时,所有到MySQL的Hikari数据库池连接都处于打开和空闲状态。我在spring applicationContext文件中使用JNDI查找从Jetty上下文文件检索数据源 因为我不能像定义数据源bean那样在jndi查找中指定destroy方法,所以我提到了这个问题:,其中提到可以尝试在ServletContextListener的contextDestroyed()方法

我在Spring和Jetty 9中使用HikariCP 2.3.3,并试图解决这样一个事实:当我热部署一个新的war文件时,所有到MySQL的Hikari数据库池连接都处于打开和空闲状态。我在spring applicationContext文件中使用JNDI查找从Jetty上下文文件检索数据源

因为我不能像定义数据源bean那样在jndi查找中指定destroy方法,所以我提到了这个问题:,其中提到可以尝试在ServletContextListener的contextDestroyed()方法中关闭数据源。在这种情况下,他们使用的是tomcat和c3po,所以我不确定这个例子有多相关

我在我的contextDestroyed方法中尝试了以下方法:

InitialContext initial;
DataSource ds;     

try
{
   initial = new InitialContext();
   ds = (DataSource) initial.lookup("jdbc/myDB");
   if (ds.getConnection() == null)
   {
       throw new RuntimeException("Failed to find the JNDI Datasource");
   }

   HikariDataSource hds = (HikariDataSource) ds;

   hds.close();
} catch (NamingException | SQLException ex)
{
   Logger.getLogger(SettingsInitializer.class.getName()).log(Level.SEVERE, null, ex);
}
但在HikariDataSource hds=(HikariDataSource)ds;我得到以下异常:
java.lang.ClassCastException:com.zaxxer.hikari.HikariDataSource无法转换为com.zaxxer.hikari.HikariDataSource

在GitHub上阅读本期文章后,我还尝试了以下内容:

但是我得到了以下异常:
java.sql.SQLException:Wrapped connection不是com.zaxxer.hikari.HikariDataSource类的实例
在com.zaxxer.hikari.HikariDataSource.unwrap(HikariDataSource.java:177)

我觉得我已经接近一个可行的解决方案了,但还不能完全得到它。关闭JNDI HikariCP数据源的正确方法是什么,无论是在contextDestroyed()中还是在其他地方?

我找不到与上面的
HikariDataSource.java:177
行号对应的行。一项建议是升级到HikariCP的最新版本2.3.8

虽然您的代码看起来正确,但我怀疑您遇到了类加载器问题,Jetty/Spring类加载器加载并在JNDI中注册的HikariDataSource(类)与在web应用中加载HikariDataSource的类加载器不同

一种快速检查方法是记录/打印两个类实例,如下所示:

如果两个类对象具有不同的哈希代码,则它们不是同一个类。在这种情况下,您必须调查JNDI实例是否在“全局JNDI上下文”中注册。如果是,则该数据源可以在web应用程序实例之间共享,并且您的web应用程序不适合单方面关闭它

更新:对不起,我错过了。重读你的问题,我的猜测是正确的。您的原始错误:

java.lang.ClassCastException: com.zaxxer.hikari.HikariDataSource cannot be cast to
    com.zaxxer.hikari.HikariDataSource
很明显,有两个类加载器加载了HikariDataSource类的两个独立实例。第一个是Jetty类加载器(JNDI),第二个是web应用程序类加载器

这表明该池是跨web应用程序共享的,您可能不应该尝试从应用程序上下文中将其关闭。

我找不到与上面的
HikariDataSource.java:177
行号对应的行。一项建议是升级到HikariCP的最新版本2.3.8

虽然您的代码看起来正确,但我怀疑您遇到了类加载器问题,Jetty/Spring类加载器加载并在JNDI中注册的HikariDataSource(类)与在web应用中加载HikariDataSource的类加载器不同

一种快速检查方法是记录/打印两个类实例,如下所示:

如果两个类对象具有不同的哈希代码,则它们不是同一个类。在这种情况下,您必须调查JNDI实例是否在“全局JNDI上下文”中注册。如果是,则该数据源可以在web应用程序实例之间共享,并且您的web应用程序不适合单方面关闭它

更新:对不起,我错过了。重读你的问题,我的猜测是正确的。您的原始错误:

java.lang.ClassCastException: com.zaxxer.hikari.HikariDataSource cannot be cast to
    com.zaxxer.hikari.HikariDataSource
很明显,有两个类加载器加载了HikariDataSource类的两个独立实例。第一个是Jetty类加载器(JNDI),第二个是web应用程序类加载器


这表明该池是跨web应用程序共享的,您可能不应该尝试从应用程序上下文中将其关闭。

没错,这两个对象返回了不同的哈希代码。我们打算将数据源设置为仅限于web应用程序上下文。我在上下文文件中使用org.eclipse.jetty.webapp.WebAppContext类,但没有设置scope参数。但是,现在当我将其设置为reference WebAppContext时,我无法在contextdestromed()中使用“jdbc/myDB”查找数据源。我得到一个
javax.naming.NameNotFoundException;剩余名称“jdbc/myDB”
但是,当我的应用程序启动时,它仍然位于正确的位置。如果相关,我使用的是hibernate hikaricp依赖项版本4.3.10.Final,其中包括hikaricp-java6版本2.3.3I,如果我将其更改为:
initContext=new InitialContext();envContext=(Context)initContext.lookup(“java:comp/env”);ds=(数据源)envContext.lookup(“jdbc/myDB”)但我以后仍然会遇到不同的哈希和相同的强制转换异常。这可能不再是HikariCP问题,而只是Spring/Jetty/JNDI问题。如果您可以简化问题(通常围绕JNDI)并再次提问,您可能会得到更快的帮助。类似于“Jetty+JNDI数据源查找问题”的东西就可以了。谢谢你指引我正确的方向。你是对的,这两个对象返回了不同的哈希代码。我们打算将数据源设置为仅限于web应用程序上下文。我在上下文文件中使用org.eclipse.jetty.webapp.WebAppContext类,但没有设置scope参数。但是,现在当我将其设置为reference WebAppContext时,我无法在contextdestromed()中使用“jdbc/myDB”查找数据源。我得到一个
javax.naming.NameNotFoundException;剩余名称“jdbc/myDB”
但仍然是
java.lang.ClassCastException: com.zaxxer.hikari.HikariDataSource cannot be cast to
    com.zaxxer.hikari.HikariDataSource