August 17, 2005

Spring AOP rocks (as expected ;))

Writing about web page http://static.springframework.org/spring/docs/1.2.x/reference/aop.html#aop-pfb

So in general, I am a big fan of the decorator pattern. This pattern very nicely allows you to have individual wrappers that deal with a single concern, for example:

interface SomeService {
  Object doSomething(final Object param);
}

if you want to wrap this with a caching wrapper, then a DelegateDecorator works well:

final class CachingSomeService implements SomeService {
  private final SomeService delegate;
  private final Map map = new HashMap();
  public CachingSomeService(final SomeService theDelegate) {
    this.delegate = theDelegate;
  }

  public final Object doSomething(final Object param) {
    if (!map.contains(param)) {
      map.put(param, delegate.doSomething(param));
    }
    return map.get(param);
  }
}

you get the idea ;)

Well this works really well unless you only want to provide extra functionality for a single method, in which case you end up with a lot of methods that don't do anything except delegate, which is a bit smelly.

Spring AOP (actually just AOP) provides the answer ;) If you aren't familiar with, or haven't used AOP, then it takes a while to get your head around what it is, and how it works. Coupled with the fact that they use the most stupid terminology ever; it isn't easy :)

Anyways, rather then create another decorator, I now create an MethodInterceptor. This is a bit of code "wraps" the method I am adding functionality to. It looks like:

public Object invoke(final MethodInvocation methodInvocation) throws Throwable {
        Object[] args = methodInvocation.getArguments();
        Object param = args[0];
        if (!map.contains(param)) {
          map.put(param, methodInvocation.proceed());
        }
        return map.get(param);
    }

(one nasty thing is you loose type safety :()

I then need to tell Spring to wrap the bean with this interceptor. I do this by using a pointcut. A pointcut basically defines a position within code. Spring has a concept of an Advisor (combination of Advice and Pointcut), and a useful regexp based implements:

bean id="cachingAdvisor" class="org.springframework.aop.support.RegexpMethodPointcutAdvisor"
    property name="advice" ref="cachingMethodInterceptor"
    property name="patterns"
      list
        value .* value 
      list
    property
  bean

So we now have an Advisor detailing what we want to do, and where we want to do it.

The final piece is to "wrap" the "delegate", the original service implementation. We can do that through a FactoryBean, specifically, a ProxyFactoryBean:

bean id="myServiceTarget" class="MyServiceImpl"

   bean id="myService" class="org.springframework.aop.framework.ProxyFactoryBean"
    property name="proxyInterfaces" value="MyService"
    property name="target" ref="myServiceTarget"
    property name="interceptorNames"
      list
        value cachingAdvisor value
      list
    property
  bean

Thus, when anyone asks for the bean "myService" they get a proxy that delegates all matching methods to cachingAdvisor. Any methods that don't match go straight through to the delegate (myServiceTarget).

Cool eh ;)

OK, as always there are pros and cons, pros:

  • cut down and empty delegateDecorators
  • configuration is done in the XML, where it should be
  • reuse advisor whereever (imagine a debugging advisor which will work for any method ;))

cons:

  • configuration is quite complicated
  • refactoring will break the advisor because of the lack of type safety. It will also potentially break the pointcut declaration
  • have to look at the configuration to see what is being done (which might actually be a good thing ;))
  • easy to break a whole chain of things because it is not being applied where you think it is
  • difficult to debug because you cannot see which classes are being used, you only see a "proxy$x" class.

Still all in all, an extremely powerful thing. It really comes into it's own when you start applying the same bit of code to lots of different places, i.e. transactions, security etc.


- One comment Not publicly viewable

  1. Chris May

    I see two different use cases for this kind of thing:

    a) Framework–type things – for example persistence, audit, transactions, or security. Here you're typically applying the same advice to the same method on a whole bunch of implementations of the same interface (i.e. SomeController.doWork()). In this case AOP is undeniably great – it allows you to separate your domain from all the supporting cruft in a very unobtrusive way, and the dangers of loss of type–safety and hard–to–trace code are minimal.

    b) Difficult domain logic. Here I'm less convinced. If you're invoking AOP to implement domain logic, you're likely to be advising a single method, in a way which is far from obvious to the maintainer. In 99% of cases I think that when a requirement to use AOP in the domain is identified, it really boils down to a failure to model the domain objects correctly. If you have to use AOP in the domain, then configuring it with annotations rather than external XML adds a small degree of extra traceability, and hints to the maintainer that there might be a tight coupling between the advisor and the advised.

    sometimes you can get around point (b) by re–defining that part of your domain to be part of the framework :–)

    17 Aug 2005, 13:39


Add a comment

You are not allowed to comment on this entry as it has restricted commenting permissions.

August 2005

Mo Tu We Th Fr Sa Su
Jul |  Today  | Sep
1 2 3 4 5 6 7
8 9 10 11 12 13 14
15 16 17 18 19 20 21
22 23 24 25 26 27 28
29 30 31            

Search this blog

Tags

Galleries

Most recent comments

  • Interesting… While I'm not completely convinced in such microbenchmarks, I'm pretty sure that 1ms = … by Alexander Snaps on this entry
  • Hello. I bought the book yesterday. I was trying to find the source code for chapter 11 and chapter … by Suleman on this entry
  • http://woosight.net/account/login?username=demo by live mashup demo on this entry
  • Thanks mate .. This blog was really helpful. by Maaz Hurzuk on this entry
  • Ty. Not directly helpful for my problem, but pointed me in the right direction. You will also get th… by Mike E. on this entry

Blog archive

Loading…
Not signed in
Sign in

Powered by BlogBuilder
© MMXIV