getMethod(”methodA”)
에서 메서드 이름이 틀리면 컴파일 시점에선 오류가 없다.)public interface InvocationHandler {
Object invoke(Object proxy, Method method, Object[] args) throws Throwable;
}
Object proxy
: 프록시 자신Method method
: 호출한 메서드Object[] args
: 메서드를 호출할 때 전달한 인수public class TimeInvocationHandler implements InvocationHandler {
private final Object target;
public TimeInvocationHandler(Object target) {
this.target = target;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
log.info("TimeProxy 실행");
long startTime = System.currentTimeMillis();
Object result = method.invoke(target, args);
long endTime = System.currentTimeMillis();
long resultTime = endTime - startTime;
log.info("TimeProxy 종료 resultTime={}", resultTime);
return result;
}
}
Object target
: 동적 프록시가 호출할 대상method.invoke(target, args)
: 리플렉션을 사용해서 target 인스턴스의 메서드를 실행한다.AInterface target = new AImpl();
AInterface proxy = (AInterface) Proxy.newProxyInstance(
AInterface.class.getClassLoader(),
new Class[]{AInterface.class},
new TimeInvocationHandler(target)
);
proxy.call();
new TimeInvocationHandler(target)
: 동적 프록시에 적용할 핸들러 로직이다Proxy.newProxyInstance(AInterface.class.getClassLoader(), new Class[]
{AInterface.class}, handler)
java.lang.reflect.Proxy
를 통해서 생성할 수 있다.InvocationHandler
를 통해 부가 기능만 정의하면 동적으로 프록시 클래스를 만들어낼 수 있다.Code Generator Library
public interface MethodInterceptor extends Callback {
Object intercept(Object var1, Method var2, Object[] var3, MethodProxy var4) throws Throwable;
}
obj
: CGLIB가 적용된 객체method
: 호출된 메서드args
: 메서드를 호출하면서 전달된 인수proxy
: 메서드 호출에 사용public class TimeMethodInterceptor implements MethodInterceptor {
private final Object target;
public TimeMethodInterceptor(Object target) {
this.target = target;
}
@Override
public Object intercept(Object obj, Method method, Object[] args, MethodProxy methodProxy) throws Throwable {
log.info("TimeProxy 실행");
long startTime = System.currentTimeMillis();
Object result = methodProxy.invoke(target, args);
long endTime = System.currentTimeMillis();
long resultTime = endTime - startTime;
log.info("TimeProxy 종료 resultTime={}", resultTime);
return result;
}
}
Object target
: 프록시가 호출할 실제 대상proxy.invoke(target, args)
: 실제 대상을 동적으로 호출한다.
MethodProxy proxy
를 사용하는 것을
권장한다.Enhancer enhancer = new Enhancer();
enhancer.setSuperclass(ConcreteService.class);
enhancer.setCallback(new TimeMethodInterceptor(target));
ConcreteService proxy = (ConcreteService) enhancer.create();
proxy.call();
Enhancer
: CGLIB는 Enhancer
를 사용해서 프록시를 생성한다.enhancer.setSuperclass(ConcreteService.class)
enhancer.setCallback(new TimeMethodInterceptor(target))
enhancer.create()
enhancer.setSuperclass(ConcreteService.class)
에서 지정한 클래스를 상속 받아서 프록시가 만들어진다.
CGLIB가 동적으로 생성하는 클래스 이름은 다음과 같은 규칙으로 생성된다.
대상클래스$$EnhancerByCGLIB$$임의코드
참고로 다음은 JDK Proxy가 생성한 클래스 이름이다.
proxyClass=class com.sun.proxy.$Proxy1