-
JDK Dynamic Proxy vs CGLib Proxyspring 2019. 5. 13. 11:57
개요
Spring AOP는 2가지 타입의 proxy를 제공한다. 바로 JDK Dynamic Proxy와 CGLib Proxy이다. Spring AOP의 ProxyFactoryBean이 proxy를 생성하는데, 경우에 따라 이 둘 중 하나를 선택해서 사용하는 방식이다. 각 Proxy가 어떻게 다르고 어떤 경우에 쓰이는지 살펴보자.
JDK Dynamic Proxy
JDK Dynamic Proxy는 interface 기반의 proxy이다. 이는 큰 단점인데, 왜냐하면 모든 target class가 interface를 구현하고 있어야하기 때문이다. 또한, JDK Dynamic Proxy는 Java reflecton을 사용해 method를 invoke한다. 이를 이해하기 위해 먼저 Java reflection을 살펴보자.
Java reflection
Java reflecton은 구체적인 class type을 몰라도 그 class의 method, type, variables에 접근할 수 있게 해주는 기능이다.
때로는 구체적인 class type을 알지못하지만 동적으로 instance를 생성해야 할 때가 있다.(인자로 class name을 넘겨 받는 경우를 생각해보자.) 그럴 때에 사용하는 기능이다. Java class file들은 binary code로 compile되어 static 영역에 존재하게 된다.
따라서, class type을 모르더라도 class명을 알면 class를 찾을 수 있다. 예제는 다음과 같다.
public static void loadAndExecute(String className) throws Exception{ Class c = null; c = Class.forName(className); Object target = c.newInstance(); Method m = c.getDeclaredMethod("setMessage", String.class); m.invoke(target, "Hello"); m = c.getDeclaredMethod("handle"); m.invoke(target); }
참고: https://brunch.co.kr/@kd4/8
http://egloos.zum.com/lemonfish/v/4087285
JDK Dynamic Proxy는 위의 Java reflection을 사용해 target class의 method를 invoke하는데, 이는 성능 저하를 야기한다.
또한, target class의 모든 method가 Advice되지 않을지라도, JDK Dynamic Proxy는 일단 invoke하고 이후에 Advice되는 method인지 아닌지를 판단한다. 따라서, 더욱 성능이 저하된다.
JDK Dynamic Proxy를 정리하면 이렇다.
- interface를 구현하는 class들만 target이 될 수 있다.
- Java reflection을 사용해 target class의 method를 invoke하며, Advise대상이든 아니든 모든 method call마다 reflection invoke를 실시하므로 성능이 떨어진다.
CGLib Proxy
CGLib Proxy는 interface의 유무와 상관 없이 적용될 수 있다. 또한, Java reflection이 아닌 bytecode를 사용해(구체적인 과정은 모르겠음) target class의 method를 호출한다. 이러한 방식은 한 번의 method 호출 후에는 생성된 bytecode를 재사용할 수 있어 실행 속도가 향상된다. 또한, Spring 3.2부터 CGLib library가 Spring framework에 포함이 되면서 별도의 라이브러리 설정 없이도 사용 가능하게 되었다. 성능 면에서 더 우수하고, interface를 굳이 만들지 않아도 쓸 수 있다는 점에서 JDK Dynamic Proxy보다 모두 좋아 보인다. 그러나, 한 가지 단점은 'final'이 붙은 class나 method에 대해서는 쓸 수 없다는 것이다.
따라서, 정리하면 이렇다.
- interface가 없어도 사용 가능
- bytecode 사용해 target class의 method 호출
- 'final' class or method에는 쓸 수 없음
Spring AOP의 ProxyFactoryBean의 두 proxy 사용
ProxyFactoryBean은 interface의 유무로 proxy를 자동으로 설정한다. interface를 하나 이상 구현하고 있는 class라면 JDK Dynamic Proxy를 생성한다. 반대로 interface를 전혀 구현하고 있지 않는 class라면 CGLib proxy를 생성한다.
그러나, 명시적으로 특정 proxy를 사용하도록 선언할 수 있다. ProxyInterfaces property value를 1개 이상 설정하면 JDK Dynamic Proxy를 쓴다. 물론, 어차피 interface를 구현하고 있는 class라면 자동으로 JDK Dynamic Proxy를 쓰기 때문에 안써도 문제는 없다.
결국 사용되는 case는 interface를 구현하고 있지만, CGLib proxy를 사용하고 싶을 때뿐일 것이다. ProxyTargetClass property를 true로 설정하면, CGLib proxy를 쓰겠다는 것이다. 반대로 false로 설정하면 쓰지 않겠다는 것이다.
→ (주의) false로 설정했다 할지라도, target class가 interface를 구현하고 있지 않은 경우에는 CGLib proxy를 쓴다.
ex.
<aop:config proxy-target-class="true">
참고
'spring' 카테고리의 다른 글
Spring Webflux - Functional Endpoints (0) 2019.07.25 Spring Webflux - DispatcherHandler (0) 2019.07.18 Spring WebClient (0) 2019.07.10 Spring Webflux + Reactor (0) 2019.05.13 Spring AMQP (0) 2019.05.13