Wednesday, February 01, 2006

Spring AOP

I've generally been a bit sceptical about the applicability of aspect-oriented programming (AOP). There seemed to be a lot of hype coming out of places like IBM about AspectJ, but I could never see this really taking off, as it is really a different language, rather than an extension to Java. Kevin Sullivan (et al) have an interesting paper which balances some of the benefits and some of the problems, using AOP to design software. After reading this I was still thinking that aspects might not be that useful.

However, I've recently been looking at the AOP support in Spring, which gives the programmer an API to use, rather than extra programming language constructs. Although this restricts what is possible to a certain degree, it does allow AOP to be used in "normal Java programs", especially as one of the tenets of Spring's design philosphy is to be non-invasive. I have managed to add two useful aspects to my current project, without changing the existing source code, but just by adding some new classes, and some configuration. Spring then weaves its magic to connect things up at runtime (using a lot of reflection and dynamic proxies behind the scenes). Regardless of this, I was pretty impressed.

In the application I am working on at the moment, we are calling a number of external web services, and we have been somewhat concerned with the performance of these. We wanted to measure how long calls to the web services take to complete. By using an aspect, we can write the profiling code in one place, and apply it across all of our web service calls. By configuring it in the Spring application context, we can also insert or remove the profiling code without having to alter the Java source.

I wrote the following simple class, which implements an interface from the Spring API, to implement some around advice. There's a lot of terminology used in AOP, for a quick guided tour, see this glossary.

public class SimpleProfilingAdvice implements MethodInterceptor {

public Object invoke(MethodInvocation invocation) throws Throwable {

StopWatch sw = new StopWatch();
sw.start(invocation.getMethod().getName());
Object returnValue = invocation.proceed();
sw.stop();

report(invocation, sw.getTotalTimeMillis());
return returnValue;
}

private void report(MethodInvocation invocation, long ms) {
// print out the timing info etc
}
}

Then in the configuration, I just add:

<bean id="webServiceFacade" class="WebServiceFacadeImpl" />

<bean id="profiler" class="SimpleProfilingAdvice">

<bean id="proxyCreator" class="org.springframework.aop.framework.autoproxy.BeanNameAutoProxyCreator">
<property name="beanNames">
<list><value>webServiceFacade</value></list>
</property>
<property name="interceptorNames">
<list>
<value>profiler</value>
</list>
</property>
</bean>

Spring automatically creates a proxy for my webServiceFacade bean, which intercepts calls, and runs my advice instead (which in turn, proceeds to call the original method).

In the same vein, I took the ideas presented by Tom White in his article on using memoization for caching, and created a caching aspect. I could then chain this together with my profiling aspect to compare performance of the calls with and without caching.





<< Home

This page is powered by Blogger. Isn't yours?