Search code examples
springspring-bootaop

Spring AOP does not work with self-invocation such as @CachePut


I'm working on Spring caching annotation, but i found some weird things happening in it.

Say I am calling a method in the same service class that has @CachePut annotation in it. That is not getting cached.

If i move that method to some other service implementation file and calling that method caching is working.

I need to know what i'm doing wrong.


Solution

  • Suppose you write the following class with @CachePut ,

    public class FooBean implements Foo{
    
        @CachePut
        public String doSomething(){
    
        }
    }
    

    Spring behind scene will create an AOP proxy that wrap your class such that it can apply some caching magic codes before or after calling the actual @CachePut method. You can think the AOP proxy looks likes :

    public class FooBeanProxy implements Foo{
    
        private FooBean fooBean;
    
        public String doSomething(){
    
            //Maybe there are some caching magic codes here....
            fooBean.doSomething()
            //Maybe there are other caching magic codes here........
        }
    }
    

    If i move that method to some other service implementation file and calling that method caching is working.

    Suppose you do the following in order to call @CachePut method:

    @Component
    public class App {
    
        //FooBeanProxy actually injected HERE
        @Autowired
        private Foo foo;
    
        public void startDoing(){
            foo.doSomething();
        }
    }
    

    What Spring injects for you is FooBeanProxy,but not your FooBean. So, when you call that @CachePut method , the caching magic codes will run as you are calling FooBeanProxy

    Say I am calling a method in the same service class that has @CachePut annotation in it. That is not getting cached.

    That means it is self-invocation . What you are invoking is this reference , which is your FooBean instance but not that FooBeanProxy anymore. So those caching magic will never be executed and hence the result will not be cached.

    Actually ,what I talk above are already mentioned in docs. If you still want to have @CachePut to take effect in the self-invocation case , you can use the horrible and ugly AopContext.currentProxy() solution mentioned in the docs or use AspectJ.