Spring AOP의 Self Invocation Issue

June Lee·2022년 5월 9일
0

Spring

목록 보기
8/9

회사에서 캐시에 custom aop를 붙여서 사용하는데, 그 과정에서 self invocation issue를 모르는 나와 같은..경우 때문에 문제가 발생했다.




Self Invocation?

AOP의 self invocation(자기 호출)은 같은 클래스 내에서 AOP가 붙은 메서드에 접근하는 상황을 말한다.
그리고 AOP는 이런 self invocation 상황에서 제대로 동작하지 않는다.
그 이유는 AOP가 내부적으로 프록시 빈을 사용하기 때문이다. Spring AOP는 빈을 생성하는 시점에 AOP가 적용된다는 프록시 빈을 생성해주는데, 이 프록시 빈은 지정된 메소드가 호출될때 이 타이밍을 가로채어서 다른 동작들을 할 수 있도록 해주는 역할을 한다.
그런데, AOP 어노테이션이 붙은 메서드와 붙지 않은 메서드가 같은 클래스에 속할 경우, 프록시 빈을 이용하는게 아니라 this.{methodName}과 같은 식으로 self invocation을 하기 때문에 AOP를 탈 수 없다.

public class Example {


    @Cachable(...)
    public Foo test() {
        ....
        return foo;
    }

    public void run() {
        test();
    }
    

}

여기서 run 메소드가 test를 호출하게 되면 이건 self invocation이어서 $Proxy48.test 가 아닌 example를 참조하는 this.test() 가 되어서 AOP가 적용되지 않는다.

Self Invocation의 해결 방법

1.AopContext.currentProxy

public class Example {


    @Cachable(...)
    public Foo test() {
        ....
        return foo;
    }

    public void run() {
        ((Example) AopContext.currentProxy()).test();
    }
    

}

단 이 방법을 이용하기 위해서는 expose-proxy 옵션을 켜줘야한다.

<aop:aspectj-autoproxy expose-proxy="true"/>
// 혹은
ProxyFactory.setExposeProxy(true)
// 혹은 
@EnableAspectJAutoProxy(exposeProxy=true)
  1. 자기 자신의 빈을 주입받는 방법
public class Example {


	@Resouce(name="example")
    Example example;


    @Cachable(...)
    public Foo test() {
        ....
        return foo;
    }

    public void run() {
        example.test();
    }
    

}
  1. AspectJ Weaving
    Spring AOP의 Weaving이 아닌 AspectJ의 Weaving을 사용하는 방식. (이를 위해서는 aspectjrt 라이브러리가 필요하며, Monjo의 AspectJ Maven Plugin을 사용해줘야한다)

이 방식의 경우 별도 코드 수정이 필요하지 않다.




참고
Self Invocation은 왜 발생할까?
Spring - How to cache in self-invocation with aspectJ?

profile
📝 dev wiki

0개의 댓글