I am working on a project called ScoreOut that consists of an application that runs on a phone that interacts with a server via a REST API. The server is written in Java and makes heavy use of the Spring Framework. I wanted to start tracking some of the actions that a user takes on the phone and recording those actions in our analytics tables. For example, we want to record when a user logs in or requests a golf course. However, we do not want to slow down the response to the client since the customer is probably out on a golf course at that time. Therefore, it seemed to makes sense to perform any auditing asynchronously.
The server is broken up into services and I already had a service that did auditing. I added two new methods to it recordClientLogin and recordCourseRetrieval. I wanted these methods to be run asynchronously but I wanted the asychronousness (if this isn’t a word it should be) to be reusable and easily enabled or disabled (easier to unit test when disabled). This immediately let me to use AOP so I wrote an interceptor.
package com.scoreout.service.interceptor;
import org.aopalliance.intercept.MethodInterceptor;
import org.aopalliance.intercept.MethodInvocation;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
/**
* Intecepts a call and makes it asynchronous. If there is an error it is
* simply logged.
*/
public class AsynchronizeInterceptor implements MethodInterceptor
{
/**
* Logger
*/
private static final Log LOG = LogFactory.
getLog(AsynchronizeInterceptor.class);
/**
* This method will always return null since the method is
* invoked asynchronously.
*
* @see org.aopalliance.intercept.MethodInterceptor
* #invoke(org.aopalliance.intercept.MethodInvocation)
*/
public Object invoke(final MethodInvocation invocation) throws Throwable
{
Thread thread = new Thread()
{
public void run()
{
try
{
invocation.proceed();
} catch (Throwable e)
{
LOG.warn("Asynchronous method invocation failed.", e);
}
}
};
thread.start();
return null;
}
}
So this inteceptor will make any method it intercepts asynchronous running the method on a separate thread and returning immediately. So now I just needed to add the point cut to the spring application context.
<!-- Turns methods calls into asynchronous method calls -->
<bean id="asynchronizeInterceptor"
class="com.scoreout.service.interceptor.AsynchronizeInterceptor">
</bean>
<!-- Intercept caddie event recording method calls -->
<bean id="asynchronizePointCut"
class="org.springframework.aop.support.RegexpMethodPointcutAdvisor">
<property name="advice">
<ref local="asynchronizeInterceptor" />
</property>
<property name="patterns">
<list>
<value>com.scoreout.service.Audit.recordCourseRetrieval*</value>
<value>com.scoreout.service.Audit.recordClientLogin*</value>
</list>
</property>
</bean>
Now anytime I call com.scoreout.service.Audit.recordCourseRetrieval or com.scoreout.service.Audit.recordClientLogin the call will return immediately and the method will be run in the background. For testing I can easily make these methods synchronous by either removing them from the application context or providing a new application context that does not include this pointcut (I generally prefer the latter).
That was inspiring,
Keep up the good work,
Thanks for writing, most people don’t bother.