Wednesday, October 15, 2008

Spring AOP and @annotation pointcuts

I'm working on a Spring-AOP and annotation-based solution for caching web service requests. Here's the overview:

I have created an Annotation named "Cacheable", that you use like this:

public Data getData(int id)

Then using Spring's AOP functionality, I want to wrap every method that is annotated as @Cacheable in around advice that uses memcache to return cached results.

The problem I ran into was getting access to the seconds attribute of the annotation in the advice (for setting the cache timeout).

What I didn't understand, and wasn't clear to me from the Spring docs, was how to pass the annotation to the advice.

(Note: I'm using schema-based aop configuration)

Normally, if you are just trying to match methods that are annotated in a pointcut expression, you would make a pointcut definition with "@annotation(". But what if you want to have access to the annotation in the advice? Your advice looks like this:

public Object aroundCacheable(ProceedingJoinPoint pjp, Cacheable cachable) throws Throwable
  int timeout = cacheable.seconds();

Your pointcut expression has to specify what to pass as the cacheable parameter in the advice. So you have to modify the pointcut definition and add arg-names like this:

<aop:around pointcut="@annotation(cacheable)" method="aroundCacheable" arg-names="cacheable"/>

My understanding is that this tell Spring to look for an argument named cacheable in the advice method, and figure out the type from that. This seems a little strange because the pointcut definition is dependent on the advice. It seems like a pointcut should be self-contained, and not depend on how it is used. But maybe I'm missing something. I'll have to look into it more later, but for now, I'm just glad I got it working.