I need to execute several initialization statements on each borrowed connection from a Tomcat JDBC Pool. I cannot use JDBCInterceptors because pool is shared with other applications that won't need said initilization.
I'm using Spring Boot 1.4.4, deploying on Tomcat 8.5.11, which has a ResourceLink in context.xml to a Resource in server.xml that defines the DataSource against a Oracle 11g Database. I'm accessing the DataSource via JNDI.
As per this answer https://stackoverflow.com/a/38746398 I wanted to use Spring AOP to accomplish my goal.
I have created and Aspect that works perfectly if the DataSource is defined directly in context.xml, but fails with a ClassCastException if referenced via a ResourceLink to the same definition in server.xml
The exception is:
java.lang.ClassCastException: org.apache.tomcat.jdbc.pool.DataSource cannot be cast to org.apache.tomcat.jdbc.pool.DataSourceProxy at org.apache.tomcat.jdbc.pool.DataSourceProxy$$FastClassBySpringCGLIB$$26808f96.invoke(<generated>) at org.springframework.cglib.proxy.MethodProxy.invoke(MethodProxy.java:204) at org.springframework.aop.framework.CglibAopProxy$CglibMethodInvocation.invokeJoinpoint(CglibAopProxy.java:721) at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:157) at org.springframework.aop.framework.adapter.AfterReturningAdviceInterceptor.invoke(AfterReturningAdviceInterceptor.java:52) at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:179) at org.springframework.aop.interceptor.ExposeInvocationInterceptor.invoke(ExposeInvocationInterceptor.java:92) at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:179) at org.springframework.aop.framework.CglibAopProxy$DynamicAdvisedInterceptor.intercept(CglibAopProxy.java:656) at org.apache.tomcat.jdbc.pool.DataSource$$EnhancerBySpringCGLIB$$17f85659.getConnection(<generated>) My Aspect class:
import org.aspectj.lang.annotation.*; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.stereotype.Component; @Aspect @Component public class DataSourceAspect { private static final Logger LOG = LoggerFactory.getLogger(DataSourceAspect.class); @AfterReturning(pointcut = "execution(* org.apache.tomcat.jdbc.pool.DataSourceProxy.getConnection())") public void afterConnectionEstablished() { LOG.info("Borrowed connection from the pool. Initializing..."); } } ResourceLink definition in context.xml:
<ResourceLink name="jdbc/us_j2eeCoreDS" global="jdbc/us_j2eeCoreDS" type="javax.sql.DataSource"/> DataSource definition in server.xml (changed private values):
<Resource name="jdbc/us_j2eeCoreDS" type="javax.sql.DataSource" global="jdbc/us_j2eeCoreDS" factory="org.apache.tomcat.jdbc.pool.DataSourceFactory" driverClassName="oracle.jdbc.OracleDriver" username="xxx" password="xxx" initialSize="1" minIdle="1" maxIdle="4" maxWaitMillis="5000" maxActive="40" removeAbandonedOnBorrow="true" removeAbandonedTimeout="300" testWhileIdle="true" validationQuery="SELECT 1 FROM DUAL" timeBetweenEvictionRunsMillis="60000" url="jdbc:oracle:thin:@host:port:SID"/> As I said before, if I define the exact same DataSource in context.xml, it works flawlessly.
Any clue?
Thanks a lot.