The self-calling limitation in Spring-AOP and one unintrusive solution
May 29, 2007 – 19:45 | aop, java, springSpring-AOP is implemented by creating proxies decorating the target bean. One typical gotcha from using these proxies, for instance, in declarative transaction management, is the proxy can't intercept a call made from one method to another on the same target object (typically a service bean), even though both methods are supposed to be wrapped by the proxy.
One obvious solution to the problem is to always explicitly get the bean reference from the Spring context and then call the method on it, instead of calling the method on 'this'. For example, instead of this.anotherServiceMethod(), do:
-
// get hold of the application context either through
-
// a singleton locator or through a private reference, then
-
context.getBean("aServiceBean").anotherServiceMethod();
It's an easy solution, but one that doesn't come without a few nuisances. For instance, it adds to your service bean some compile-time dependencies on Spring classes that wouldn't have been necessary otherwise.
One less intrusive solution I've come up with is a AdviceSkippingInjector.java that injects the reference to any proxied Spring bean into a property on the "raw" bean, i.e., the object prior to being wrapped in the proxy.
To use it, add a proxiedSelf property to the service bean (it doesn't have to be on any public interface), add this to your context file:
-
<bean id="aService" class="your.proxied.service.Bean">
-
</bean>
-
-
<bean id="ProxySkippingInjector" class="com.digizen.commons.spring.AdviceSkippingInjector">
-
<property name="beanProperties">
-
<map>
-
<entry key="aService" value="proxiedSelf" />
-
</map>
-
</property>
-
</bean>
In the map beanProperties, each key is a bean name defined in the context, and the corresponding value a property name on the bean. At run-time, if the AdviceSkippingInjector sees a bean name in its map, it will drill into the proxies, find the reference to the original bean, and inject the reference to the proxy into the original bean's proxiedSelf property.
This solution is unintrusive because the service bean remains unaware of any of the plumbing work. All the wiring is done in the application context. In fact, the service bean isn't even necessarily aware that proxiedSelf, despite the name, points to its "proxied self".
