Spring AOP not working for method call inside another method
Update 2022:
Now I personally prefer using TransactionHandler class described here - much cleaner and flexible way.
Original answer:
It can be done by self injection usage. You can call inner method through injected instance:
@Component
public class Foo {
@Resource
private Foo foo;
public void method1(){
..
foo.method2();
..
}
public void method2(){
..
}
}
Since Spring 4.3 you also can do it using @Autowired.
As of 4.3, @Autowired also considers self references for injection, i.e. references back to the bean that is currently injected.
I had the same kind of problem and I overcame by implementing Spring's ApplicationContextAware
,BeanNameAware
and implementing corresponding methods as below.
class ABC implements ApplicationContextAware,BeanNameAware{
@Override
public void setApplicationContext(ApplicationContext ac) throws BeansException {
applicationContext=ac;
}
@Override
public void setBeanName(String beanName) {
this.beanName=beanName;
}
private ApplicationContext applicationContext;
private String beanName;
}
then I replaced this.
with ((ABC) applicationContext.getBean(beanName)).
while calling the methods of the same class. This ensures that calls to methods of the same class happen through the proxy only.
So method1()
changes to
public void method1(){
.........
((ABC) applicationContext.getBean(beanName)).method2();
...........
}
Hope this helps.
The aspect is applied to a proxy surrounding the bean. Note that everytime you get a reference to a bean, it's not actually the class referenced in your config, but a synthetic class implementing the relevant interfaces, delegating to the actual class and adding functionality, such as your AOP.
In your above example you're calling directly on the class, whereas if that class instance is injected into another as a Spring bean, it's injected as its proxy, and hence method calls will be invoked on the proxy (and the aspects will be triggered)
If you want to achieve the above, you could split method1
/method2
into separate beans, or use a non-spring-orientated AOP framework.
The Spring doc (section "Understanding AOP Proxies") details this, and a couple of workarounds (including my first suggestion above)
Spring AOP framework is "proxy" based, the documentation at Understanding AOP Proxies explains it very well.
When Spring constructs a bean that is configured with an aspect (like "ABC" in your example), it actually creates a "proxy" object that acts like the real bean. The proxy simply delegates the calls to the "real" object but by creating this indirection, the proxy gets a chance to implement the "advice". For example, your advice can log a message for each method call. In this scheme, if the method in the real object ("method1") calls other methods in the same object (say, method2), those calls happen without proxy in the picture so there is no chance for it to implement any advice.
In your example, when method1() is called, the proxy will get a chance to do what ever it is supposed to do but if method1() calls method2(), there is no aspect in the picture. However, if method2 is called from some other bean, the proxy will be able to carry out the advice.