2015년 5월 21일 목요일

Java Dynamic Proxy vs CGLib Proxy vs AspectJ Weaving #3

2. CGLib Proxy
CGLib는 바이트 코드를 조작해서 Proxy를 만듭니다.
CGLib를 사용해서 Proxy를 만들면, interface를 정의하고 구현할 필요가 없고, 다른 클래스를 상속할 수 도 있습니다.
예를 들어, Hibernate의 Entity는 POJO인데, Java Dynamic Proxy로는 lazy loading을 구현할 수 없지만, CGLib로는 가능합니다.

Java Dynamic Proxy에서 java.lang.reflect.Proxy가 했던 유사한 일은 CGLib에서는 net.sf.cglib.proxy.Enhancer 가 담당합니다.
그리고 java.lang.reflect.InvocationHander가 했던 일은 net.sf.cglib.proxy.Callback이 합니다. 그런데 Callback을 직접 사용하지 않고, 다음의 Callback sub interface 중에 하나를 선택하여 합니다.

Dispatcher: 디스패치 callback
FixedValue: proxied 메쏘드가 리턴하는 값을 그대로 리턴
LazyLoader: lazy loading callback
MethodInterceptor: "around advice" 기능을 제공하는 범용 callback
NoOp: 부모(super) 메쏘드를 그대로 호출

예제를 한번 보겠습니다.
package cglib;

import java.lang.reflect.Method;

import net.sf.cglib.proxy.MethodInterceptor;
import net.sf.cglib.proxy.MethodProxy;

public class HashCodeAlwaysZeroMethodInterceptor implements MethodInterceptor {

 public Object intercept(Object object, Method method, Object[] args, MethodProxy methodProxy) throws Throwable {

  if ("hashCode".equals(method.getName())) {

   return 0;
  }

  return methodProxy.invokeSuper(object, args);
 }
}

위 예제에서는 MethodInterceptor를 Enhancer callback으로 사용했습니다. 모든 오브젝트에 대해서 hashCode()를 호출했을 때 0을 리턴합니다.
MethodInterceptor는 InvocationHandler와 매유 유사하게 생겼습니다.

Proxy를 생성하는 방법은 다음과 같습니다.
proxy = Enhancer.create(Object.class, new HashCodeAlwaysZeroMethodInterceptor());

Enhancel.create() 메쏘드의 매개변수는
target object의 타입
callback 객체

뿐입니다. interface 구현과 관련된 것이 없습니다.
Proxy 객체를 만들 때, target object도 같이 생성됩니다. 때문에 target object를 생성하고 메모리에 저장할 필요가 없습니다.

전체 소스 코드는 https://github.com/jinwooe/dynamic-proxy-cglib-aspectj-example 에서 받을 수 있습니다

참고 사이트
http://java.dzone.com/articles/power-proxies-java
http://denis-zhdanov.blogspot.kr/2009/08/weaving-with-aspectj.html

댓글 없음:

댓글 쓰기