Blog

The problem with proxy-based AOP frameworks

18 Aug, 2006

Proxy-based AOP frameworks like the one in the Spring Framework have a not oft discussed problem. When a method in a class invokes another method in the same class (or a superclass), any interceptors on that second method are not executed. This unexpected behaviour can have serious consequences when the interceptor delivers important services like transactions or security.
Let’s say we are implementing an application for a bank where only certain employees are allowed to perform a credit check on suspect transaction, e.g. those exceeding 1 million euros. Using Aspect Oriented Programming this can be implemented as follows:

When processed by AspectJ’s precompiler, the following woven class is output:

As you can see in the picture, when the method processPayment is invoked, the correct security check is performed when the checkCreditRating method is invoked.
However, that precompilation step was perceived as complicated and hard to integrate into the build proces (and not every IDE has appropiate plugins). This led to the appearance of proxy-based AOP solutions such as dynaop and Spring’s AOP framework. A precompilation step is no longer necessary. Instead, a proxy is created on the fly. This proxy performs the functionality defined in the aspect before (and after) invoking the method in the original object:

Apart from only offering method interception instead of the full range of AOP functionality, this approach has one other, not often discussed, drawback. When invoking the checkCreditRating method on the proxy, the security check is correctly performed. However, when invoking the processPayment method on the proxy (see the picture), control is passed to the processPayment method in the original object which invokes this.checkCreditRating() directly, thereby bypassing the security check. This occurs because this in the original object refers to that object itself instead of the proxy.
Other functionality that assumes the identity of the proxy and the identity of the original object are identical will fail too. As mentioned in GoF on page 178 when discussing the Decorator pattern:

3. A decorator and its component aren’t identical. A decorator acts as a transparent enclosure. But from an object identity point of view, a decorated component is not identical to the component itself. Hence you shouldn’t rely on object identity when you use decorators.

This is an unexpected result of the proxy-based implementation of AOP and one that you need to be especially aware of when implementing important functionality in a aspect!

guest
8 Comments
Oldest
Newest Most Voted
Inline Feedbacks
View all comments
Alef Arendsen
15 years ago

Hi Vincent,
yes, provy-based AOP solution do have this specific drawback, although I haven’t seen it become a real bottleneck in any of the projects I’ve encountered. Good to spread the word though, as knowing about it is a good first step.
Your security use case is one situation where the problem might occur, another is different propagation levels on method within the same class.
class MyClass {
// propagation=REQUIRES
void doIt() {
this.doIt2();
}
// propagation=REQUIRES_NEW
void doIt2() {
}
}
Note that Load-Time-Weaving (LTW) has solved lots of the deploytime configuration problems that AspectJ used to come with. Using LTW does involve some additional configuration, but you don’t necessarily have to issue a post compilation step anymore. This works nicely together with the new Java 5 agents.
cheers,
Alef

Erwin Bolwidt
15 years ago

Hi Vincent & Alef,
In applications where one comes across this issue occasionally, and one is not ready to use LTW, one can use the AopContext solution.
On any ProxyFactoryBean you can set the ‘exposeProxy’ property to ‘true’ (it is false by default, for performance reasons, but the performance impact is very small.)
This property cooperates with the class org.springframework.aop.framework.AopContext, in such a way that it makes the AOP proxy available to the proxied instance.
Sounds complicated?
An example:
Say your BankService’s processPayment method needs to call checkCreditRating, but needs all security inerceptors to be invoked.
Instead of calling this.checkCreditRating(), it calls
BankService proxy = (BankService) AopContext.getCurrentProxy();
proxy.checkCreditRating();
It won’t receive any awards for beautiful code, but if not too frequently used, it is a good workaround.
I’ve used it in practice with one addition: to make unit testing easier; adding a fallback to an injectable property in the case that AopContext didn’t return a value. (Which occurs when running the code without an interceptor, in a unit test)
Regards,
Erwin

Alex Popescu
15 years ago

The entry is quite interesting, but it needs a small correction: AspectWerkz is/was not a proxy-based AOP solution. It offered an additional functionality to work with proxies, but the core was a weaving based AOP solution (it performed the weaving with the help of classloaders).
./alex

.w( the_mindstorm )p.
AspectWerkz developer

Patrick Vanbrabant
Patrick Vanbrabant
15 years ago

Erwin,
Regarding the AopContext solution, I think this is not a real solution anyway.
In this case the class itself must know that there is an advise applied to some of its methods. In the case of the BankAccount this may seam trivial, but lets look at an even more down to earth example.
The textbook case for applying Aop would be logging or monitoring. Lets assume that we have a simple logging advice that we want to apply on each method of the interface.
Then the developer of each class must know whether this class will always have the advide applied to it. Sounds a little like mixing of concerns.
If we then want to turn of (and on again) the logging in a production environment we have to change all the code again. Like I saym not a real solution.
Just my five cents.
KR
Patrick

trackback

[…] 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! […]

Explore related posts