티스토리 뷰

간혹 커뮤니티 등에서 AOP 에 대한 얘기를 하면 많이들 잘 알고있는 내용이 이렇다.

"spring 에서는 인터페이스가 있으면 기본적으로 JDK 에서 제공하는 dynamic proxy 를 이용하고, 없으면 CGLIB 를 이용한 상속 기반 프록시를 구현해서 AOP 를 구현한다."

나도 머리로는 잘 이해하고 있긴한데 돌이켜 생각해보면 제가 작성하는 AOP 가 dynamic proxy 로 도는지, CGLIB 로 돌아가는지에 대해 크게 고민해본적이 없다. 그리고 더 곰곰히 생각해보면 dynamic proxy 로 돌아가는 AOP 를 본적이 거의 없다.

 

그리고 실제로 인터페이스를 구현하게 해서 AOP 를 사용하면 인터페이스가 있음에도 불구하고 CGLIB 로 도는걸 볼 수 있다!

(참고로 포스팅 작성 시점 기준 spring boot 2.4.5)

// 인터페이스를 이용한 Service 클래스에 AOP 를 걸었을때 구현 클래스 로그
AopServiceImpl$$EnhancerBySpringCGLIB$$cc5a6be3

알고있던 지식과는 좀 다른 방식으로 동작하는건데 왜 CGLIB 로 도는걸까? 이런저런 내용들을 보다가 EnableAspectJAutoProxy 애노테이션을 이용하면 될 것 같다. 

/**                                                                             
 * Indicate whether subclass-based (CGLIB) proxies are to be created as opposed 
 * to standard Java interface-based proxies. The default is {@code false}.      
 */                                                                             
boolean proxyTargetClass() default false;                                       

javadoc 만 봐도 딱 이 애노테이션이 적절한것 같은데 이 애노테이션의 proxyTargetClass 를 false 로 설정해도 여전히 CGLIB 로 도는걸 볼 수 있다.

 

이 문제의 범인은 기본 설정에 있는데 spring boot 는 properties 를 통해 아래 두개의 속성을 지원하고 있다.

spring.aop.auto(default true)
spring.aop.proxy-target-class(default true)

spring.aop.auto 는 @EnableAspectJAutoProxy 를 자동으로 설정해주는 역할을 한다. default 값은 true 이기 때문에 따로 설정하지 않는 이상 @EnableAspectJAutoProxy 애노테이션은 항상 달려있다고 보면 된다. 그래서 우리가 추가로 달아줬던 @EnableAspectJAutoProxy 설정이 먹히지 않은 것이다.

 

해당 애노테이션은 AOP 를 위해 필요한 설정이므로 기본으로 달려있는게 좋은 것 같다. 더 문제는 아래있는 spring.aop.proxy-target-class 속성인데 이 속성은 이름만 봐도 알아챘겠지만 @EnableAspectJAutoProxy 애노테이션 안에 있는 proxyTargetClass 속성을 설정하게 된다. 그리고 default 값은 true 이다.

 

애노테이션 내부의 기본 값은 false 이지만 properties 를 통해 true 로 자동으로 변경하고 있던 것이다. spring.aop.auto 속성을 false 로 주게되면 애플리케이션 내부에 있는 @EnableAspectJAutoProxy 애노테이션 설정을 따라가게되므로 자연히 proxyTargetClass 값은 (따로 변경하지 않는다면) false 가 된다. 그게 아니면 spring.aop.proxy-target-class 속성만 false 로 변경해도 된다.

 

여튼 속성을 알맞게 설정한 후 코드를 돌려보면

// 인터페이스를 이용해 AOP 를 구현한 프록시 클래스 로그
com.sun.proxy.$Proxy74
// 인터페이스 없이 클래스만 이용해 AOP 를 구현한 프록시 클래스 로그
AopConcreteService$$EnhancerBySpringCGLIB$$4ba35e46

처음에 알고있던대로 인터페이스를 구현한 경우엔 dynamic proxy 를, 인터페이스가 없는 경우에는 CGLIB 를 이용한 것을 볼 수 있다.

참고로 JDK dynamic proxy 는 예전에 이런 포스팅을 작성한 적 있다.( multifrontgarden.tistory.com/228 )

댓글
댓글쓰기 폼