After my initial explorations of the AspectJ-support offered by Spring, someone (actually, I think it was google again) pointed me to this article about the drawbacks of proxied aop. A good read written by Vincent Partington that shows the internals of how and why a proxy based aop framework can ignore your carefully injected aspects. A ‘must-be-aware-of’ for every Spring 2.0 user!
One commenter on Vincent’s entry suggested one could use the not so stunning but efficient AopContext.getCurrentProxy() call instead of refering to the ‘this‘ pointer. Besides being not beautiful (actually it is butt ugly but that’s a matter of taste which reminds me that programming just like cooking is actually all about (good) taste), getting hold of a proxied twin is in complete contradiction with all principles of aop: Code and cross cutting concerns should be seperated. The fact code needs to be aware of being proxied is more a showstopper than a workaround.
Nevertheless, once accepted this contradictious aproach, the idea came in mind to address this as just an aspect of implementation, an architectural constraint so to speak: ‘Every class or method that is subject of being proxied must be aware of its proxy object‘ (Note, I still do not agree with this rather bold statement, it is just a hypothetical aspect that I’m using for the sake of the nation to have some fun with Spring AOP). How can such an aspect being implemented using Springs AOP features?
First of all, somehow a mechanism must be in place to denote proxy aware classes. To do so, I introduced a special annotation:
public @interface Proxied {}
And of course some point cuts reflecting the usage of this annotation are required:
@Pointcut(”@within(com.logicacmg.acsa.annotations.Proxied)”)
public void withinProxiedType() {}
@Pointcut(”@annotation(com.logicacmg.acsa.annotations.Proxied)”)
public void executingProxiedMethod() {}
The first pointcut refers to classes declared with the @Proxied annotation, the second one refers to the execution of methods decorated with this annotation. Note the subtile difference, the second pointcut gives a fine grained approach were to intercept and were not.
After the pointcut definitions, it is time for some goofy advice how to deal with the proxied execution of methods:
@Before(”(withinProxiedType() || executingProxiedMethod()) && this(proxy)”)
public void beAwareOfProxiedExecution(JoinPoint jp, Object proxy) throws Throwable {
// ….. ????
}
A dirty (but what the hack, the whole problem smells) trick injecting the proxy into the usual suspecious subjects can be used at the // ….. ???? location. And for that, I’ve mixed the advice with some reflection sugar under the assumption every proxy aware class has declared a member field called ‘proxy’. The code is to long to post here but without field caching and exception catching it looks like this:
jp.getTarget().getClass().getField(”proxy”).set(jp.getTarget(), proxy);
Instead of using ((MyService)AopContext.getCurrentProxy()).someMethod it is now possible to use this.proxy.someMethod and as a bonus not every but only an exclusive set of classes is effected.
So what have I learned from this expedition? Well, not so much about the dangers of proxied aop, the previously mentioned article already let me frown. And not so much about proxy awareness either, that seems to be some kind of wicketness by nature. But more about the possibility to define annotations and put the actual semantics of these annotations in seperate aspects. And whether that is evil or not, is probably again a matter of taste. But at least it is a funny and even elegant way of processing annotations using Spring AOP.
October 24th, 2006 at 1:55 pm
Hi Okke,
Nice idea to use AOP to address a problem in AOP.
Two remarks though:
- AFAIK, AspectJ is _not_ a proxy-based AOP solution so you would not have the problem there. It’s only when using Spring 1.x’s proxy-based AOP stuff that you’d have to aware of this problem.
- You can use inter-type declarations to introduce the member “proxy” in all @Proxied classes. See
http://www.eclipse.org/aspectj/doc/released/progguide/starting-aspectj.html#inter-type-declarations
Regards, Vincent.