I have a Spring Hibernate webapp with HikariCP running on Jetty with the following context file located in the base webapps folder:
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE Configure PUBLIC "-//Jetty//Configure//EN" "http://www.eclipse.org/jetty/configure_9_0.dtd">
<Configure id='testServer' class="org.eclipse.jetty.webapp.WebAppContext">
<Set name="contextPath">/myServer</Set>
<Set name="war">C:\mypath\myServer.war</Set>
<New id="testDataSource" class="org.eclipse.jetty.plus.jndi.Resource">
<Arg><Ref refid="testServer"/></Arg>
<Arg>jdbc/myDB</Arg>
<Arg>
<New class="com.zaxxer.hikari.HikariDataSource">
<Arg>
<New class="com.zaxxer.hikari.HikariConfig">
<Set name="connectionTestQuery">SELECT 1</Set>
<Set name="dataSourceClassName">com.mysql.jdbc.jdbc2.optional.MysqlDataSource</Set>
<Set name="maximumPoolSize">20</Set>
<Set name="connectionTimeout">30000</Set>
<Set name="username">user</Set>
<Set name="password">password</Set>
<Call name="addDataSourceProperty">
<Arg>url</Arg>
<Arg>jdbc:mysql://localhost/mydb?zeroDateTimeBehavior=convertToNull</Arg>
</Call>
<Call name="addDataSourceProperty">
<Arg>user</Arg>
<Arg>user</Arg>
</Call>
<Call name="addDataSourceProperty">
<Arg>password</Arg>
<Arg>password</Arg>
</Call>
<Call name="addDataSourceProperty">
<Arg>cachePrepStmts</Arg>
<Arg>true</Arg>
</Call>
<Call name="addDataSourceProperty">
<Arg>prepStmtCacheSize</Arg>
<Arg>250</Arg>
</Call>
<Call name="addDataSourceProperty">
<Arg>prepStmtCacheSqlLimit</Arg>
<Arg>2048</Arg>
</Call>
<Call name="addDataSourceProperty">
<Arg>useServerPrepStmts</Arg>
<Arg>true</Arg>
</Call>
</New>
</Arg>
</New>
</Arg>
</New>
</Configure>
In my applicationContext.xml file I am able to successfully lookup and use the datasource using the following:
<jee:jndi-lookup id="dataSource" jndi-name="jdbc/myDB"/>
The problem I am having is that when I hot deploy a new war file, the HikariCP datasource connection pool is left open, and the connections to the database remain.
I am trying to lookup and close the datasource in the contextDestroyed()
method of a ServletContextListener
using something like the following code:
try
{
initContext = new InitialContext();
envContext = (Context) initContext.lookup("java:comp/env");
ds = (DataSource) envContext.lookup("jdbc/myDB");
if (ds.getConnection() == null)
{
throw new RuntimeException("Failed to find the JNDI Datasource");
}
logger.info("JNDI HikariDataSource : " + System.identityHashCode(ds.getClass()));
logger.info("Local HikariDataSource: " + System.identityHashCode(HikariDataSource.class));
HikariDataSource hds = (HikariDataSource) ds;
hds.close();
} catch (Exception ex)
{
logger.log(Level.SEVERE, null, ex);
}
However I am getting the following exception when trying to cast the DataSource to a HikariDataSource:
java.lang.ClassCastException: com.zaxxer.hikari.HikariDataSource cannot be cast to com.zaxxer.hikari.HikariDataSource
I am also getting different identityHashCodes above which leads me to believe that I have 2 classloaders that have loaded separate instances of the HikariDataSource class. We would like the datasource to be specific to the webapp's context and to close it on hot deployment. What do I need to change to make this happen?