Caching with AspectJ

In my last post I presented a very simple cache that stores objects. Now I want to use this cache with AspectJ in a small sample application.

You can download the Eclipse project as a tar or zip file or browse the code online here.

Implementing the aspect

I decided to use an annotation and an aspect with a pointcut that matches this annotation. All I had to do was to annotate the methods that should be cached.

Here’s the very generic version of a pointcut that matches the execution of all methods annotated with @Cachable:

@Pointcut("execution(@Cachable * *.*(..))")
private void cache() {}

The logic is this simple:

@Around("cache()")
public Object aroundProfileMethods(ProceedingJoinPoint thisJoinPoint) {
  // construct genericIdentifier
  Object obj = cache.get(genericIdentifier);
  if (obj == null) {
    obj = thisJoinPoint.proceed();
    cache.put(genericIdentifier, obj);
  }
  return obj;
}

Everytime a cachable method is executed we’ll first have a look at the cache. If there’s a cache hit we’ll immediately return the object. If there’s no such object in the cache, we’ll call the cachable method, put the returned object in the cache and finally return the object.

The genericIdentifier is a string consisting of the package-, class- and method-name and the supplied arguments. For a method named foo from a class bar inside a package called baz this might result in:

"baz.bar.foo-Integer-42"

The method foo takes one argument and at the time of this execution it was 42. This way we’ll only return objects from the cache if this generic identifier matches.

Using the aspect

All we have to do is to use the @Cachable annotation. Have a look at it:

@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
public @interface Cachable {}

It can be used with any method that returns something:

@Cachable
public BigObject getObject(final int param) {
  return new BigObject(param);
}

The first time this method is called we’ll store the object in the cache. If it’s called again with the same parameter we’ll return the object from the cache.

Conclusion

Implementing a cache is simple and so is using it with AspectJ. I presented a straightforward way to speed up any application that deals with big objects which take a long time to load. All you have to do is to use the @Cachable annotation along with the aspect. Implementing another cache in the aspect should be simple, too.

2 thoughts on “Caching with AspectJ”

  1. thanks! very good and useful tutorial!
    why didn’t you annotated directly aroundProfileMethods with @Around(“execution(@Cachable * *.*(..))”)?

  2. Hi igo,
    I think the reason for this extra method were the Around and Pointcut annotations. First you had to annotate a method with @Pointcut which in turn could be used in the Before, After and Around annotations.
    I must admit that I hadn’t have the time to look at the latest version of AspectJ; I’ll sure check it out later this year. If they’ve changed the annotations or the syntax/semantic in any way it might be possible to do the same without this extra method.

Comments are closed.