The spring framework provides an easy way for intercepting calls to methods of managed beans. In the project I am currently working at, we wanted to log access to all methods of the Connections returned by a specific datasource. This datasource is defined as a spring bean, but the connections it provides obviously aren’t.

In order to get this done, I decided intercept all calls to the getConnection() method of that specific DataSource an in stead of returning the Connection, I return a dynamic proxy to that connection which will log some method information prior to invoking that method.

Here is the source code and xml config I used to do this…

First we need to implement an interceptor for calls to the DataSource.getConnection() method. This class implements the org.aopalliance.intercept.MethodInterceptor interface:

public class ConnectionCallInterceptor implements MethodInterceptor {
 
    public Object invoke(final MethodInvocation methodInvocation) 
            throws Throwable {
 
        String methodName = methodInvocation.getMethod().getName();
        if ("getConnection".equals(methodName)) {
            // return proxied connection
            Connection connection = (Connection) methodInvocation.proceed();
            return ConnectionMethodLoggerProxy.newInstance(connection);
        } else {
            // simply return methodcall result 
            return methodInvocation.proceed();
        }
    }
}

To do the actual logging, all method calls to the java.sql.Connection need to be intercepted, here is the class that creates a dynamic proxy and does some logging in the InvocationHandler implementation:

public class ConnectionMethodLoggerProxy implements InvocationHandler {
 
    private Connection connection;
 
    public static Connection newInstance(Connection connection) {
        return (Connection) Proxy.newProxyInstance(
            connection.getClass().getClassLoader(),
            new Class[] { Connection.class },
            new ConnectionMethodLoggerProxy(connection));
    }
 
    private ConnectionMethodLoggerProxy(Connection connection) {
        this.connection = connection;
    }
 
    public Object invoke(Object proxy, Method method, Object[] args) 
            throws Throwable {
 
        String methodName = method.getName();
        String targetName = connection.getClass().getName();
        Class[] types = method.getParameterTypes();
        String returnTypeName = method.getReturnType().getName();
 
        System.out.println("=============================");
        System.out.println(" Connection method call detected:");
        System.out.println("  - Target     : " + targetName);
        System.out.println("  - Method     : " + methodName);
        System.out.println("  - Arguments  : " + ArrayUtils.toString(args));
        System.out.println("  - Arg Types  : " + ArrayUtils.toString(types));
        System.out.println("  - Return type: " + returnTypeName);
        System.out.println("=============================");
 
        return method.invoke(connection, args);
    }
}

Now we have all the code we need, all that is left to do is configure spring to actually use our ConnectionCallInterceptor whenever a method call is made to our datasource (which in this case is a bean named ‘myDataSource’):

<bean class=
    "org.springframework.aop.framework.autoproxy.BeanNameAutoProxyCreator">
    <property name="beanNames">
        <list>
            <value>myDataSource</value>
        </list>
    </property>
    <property name="interceptorNames">
        <list>
            <value>dataAccessInterceptor</value>
        </list>
    </property>
    <property name="proxyTargetClass" value="false"/>
</bean>
 
<bean id="dataAccessInterceptor" class="ConnectionCallInterceptor"/>

Although this is probably not something you’d want to do in a production environment, it helped us a great deal in our specific case. I don’t have a lot of experience with the spring framework, so there may be better ways to do this (and if you know one, please share it :)), but this looked the most straightforward to me.