JDK 동적 프록시
동적 프록시 기술을 사용하면 개발자가 직접 프록시 클래스를 만들지 않고 동적으로 프록시 객체를 런타임에 생성 할 수 있다. 또한 동적 프록시에 원하는 실행 로직을 지정하는것도 가능하다.
JDK 동적 프록시 구현
JDK 동적 프록시는 인터페이스를 기반으로 프록시를 동적으로 만들기 떄문에 인터페이스가 필수 이다.
1
2
3
public interface AInterface {
String call();
}
1
2
3
4
5
6
public class AImpl implements AInterface {@Override
public String call() {
log.info("A 호출");
return "a";
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
@Slf4j
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;
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
@Test
void dynamicA() {
AInterface target = new AImpl();
TimeInvocationHandler handler = new TimeInvocationHandler(target);
AInterface proxy =
(AInterface)Proxy.newProxyInstance(
AInterface.class.getClassLoader(),
new Class[]{AInterface.class},
handler);
proxy.call();
log.info("targetClass={}", target.getClass());
log.info("proxyClass={}", proxy.getClass());
}
TimeInvocationHandler - TimeProxy 실행
AImpl - A 호출
TimeInvocationHandler - TimeProxy 종료 resultTime=0
JdkDynamicProxyTest - targetClass=class hello.proxy.jdkdynamic.code.AImpl
JdkDynamicProxyTest - proxyClass=class com.sun.proxy.$Proxy1
로그를 보면 proxyClass=class com.sun.proxy.$Proxy1 이 부분이 동적으로 생성된 프록시 클래스 이다. 이는 개발자가 직접 만든 클래스가 아닌 JDK 동적 프록시가 이름 그래도 동적으로 만들어준 프록시 이다. 이 프록시는 TimeInvocationHandler 로직을 실행한다.
실행 순서
- 클라이언트는 JDK 동적 프록시의 call() 을 실행
- JDK 동적 프록시는 InvocationHandler.invoke()를 호출
- TimeInvocationHandler가 구현체 이므로 TimeInvocationHandler.invoke()가 호출
- TimeInvocationHandler가 내부 로직을 수행하고, method.invoke(target, args)를 호출해서 target인 실제 객체(AImpl)를 호출
- AImpl 인스턴스의 call()이 실행
- AImpl 인스턴스의 call() 종료후 TimeInvocationHandler로 응답이 반환되고 그 응답을 외부로 반환
정리
JDK 동적 프록시 기술로 인하여 적용 대상 만클 프록시 객체를 만들지 않아도 된며, 같은 부가 기능로직을 한번만 개발해서 공통으로 적용할 수 있다. 결과적으로 프록시 클래스를 수 없이 만들어야 하는 문제도 해결하고 부가 기능 로직도 하나의 클래스에 모아서 단일 책임 원칙(SRP)도 지킬 수 있다.
JDK 동적 프록시 도입 전 - 직접 프록시 생성
JDK 동적 프록시 도입 후
- $Proxy1는 개발자가 직접 만드는 클래스가 아님
참고
- 스프링 핵심 원리 - 고급편(김영한)