자바 - 동적 프록시(proxy) 기술( JDK 동적 프록시)
19404 단어 리플랙션JDK 동적 프록시JDK 동적 프록시
본 게시물은 스스로의 공부를 위한 글입니다.
잘못된 내용이 있으면 댓글로 알려주세요!
📒 리플렉션 사용 예제
- 자바 리플랙션은 여기에 잘 정리되어 있다.
- 프록시에 대한 글은 여기에 잘 정리되어 있다.
- 본 게시물의 목적은 리플렉션을 이용해 동적 프록시를 사용하는것이다.
- 간단하게 리플렉션이 어떻게 사용되는지 예제를 통해 알아보자.
🎈 리플렉션 사용 전
void reflection(){
Hello target = new Hello();
//공통 로직1 시작
log.info("start");
String result1 = target.callA();
log.info("result={}", result1);
//공톨 로직1 종료
//공통 로직2 시작
log.info("start");
String result2 = target.callB();
log.info("result={}", result2);
//공톨 로직2 종료
}
@Slf4j
static class Hello{
public String callA(){
log.info("callA");
return "A";
}
public String callB(){
log.info("callB");
return "B";
}
}
reflection
에서 두 공통 로직내에서 서로 다른 점은 호출하는 메서드가 다르다는 점이다.target.callA()
,target.callB()
그럼 메서드 호출 부분만 동적으로 처리할 수 있다면 반복되는 코드의 양을 줄일 수 있겠구나!
🎈 리플렉션 사용 후
void reflection() throws Exception {
//클래스 정보
Class classHello = Class.forName("hello.proxy.jdkdynamic.ReflectionTest$Hello");
Hello target= new Hello();
Method methodCallA = classHello.getMethod("callA");
dynamicCall(methodCallA, target);
Method methodCallB = classHello.getMethod("callB");
dynamicCall(methodCallB, target);
}
private void dynamicCall(Method method, Object target) throws Exception {
log.info("start");
Object result = method.invoke(target);
log.info("result={}", result);
}
-
Class.forName("hello.proxy.jdkdynamic.ReflectionTest$Hello")
: 클래스 메타 정보를 획득한다. 이때 클래스 위치를 적어주고, 내부 클래스는 구분을 위해$
을 사용한다. -
classHello.getMethod( {메소드명} )
: 클래스 메타 정보를 이용해 메소드 메타 정보를 획득한다. 파라미터로 호출하려는 메서드 이름을 적어준다. -
호출할 메서드 정보와 인스턴스를
dynamicCall
에게 전달하여 공통 로직을 실행한다.method.invoke( {인스턴스} )
: 인스턴스를 넘겨주며, 해당 인스턴스의 메서드를 실행한다.
위 예제에서 배운 리플렉션을 이용해 JDK 동적 프록시를 사용해보자
📒 JDK 동적 프록시
- 동적 프록시 기술을 사용하면 개발자가 직접 프록시 클래스를 만들지 않아도 된다.
- 단, 인터페이스를 기반으로 프록시를 동적으로 만들어주기 때문에, 인터페이스가 필수이다.
📌 예제
- 🎈 인터페이스 생성
public interface AInterface {
String call();
}
- 🎈 구현체 생성
@Slf4j
public class AImpl implements AInterface {
@Override
public String call() {
log.info("A 호출");
return "a";
}
}
- 🎈 JDK 동적 프록시는
InvocationHandler
인터페이스를 구현해 핸들러 객체를 리턴받는다.invoke(Object proxy, Method method, Object[] args)
Object proxy
: 프록시 자신Method method
: 호출할 메서드Object[] args
: 메서드를 호출할 때 전달한 인수
@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;
}
}
method.invoke(target, args)
: 리플렉션을 사용해서target
인스턴스의 메서드를 실행한다.args
는 메서드 호출시 넘겨줄 인수이다.
🎈 실행 테스트
- 동적 프록시는
Proxy.newProxyInstance(ClassLoader loader, Class<?>[] interfaces, InvocationHandler h
)를 통해 만들 수 있다.ClassLoader loader
: 클래스 로더 정보Class<?>[] interfaces
: 인터페이스InvocationHandler h
: 핸들러 로직
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();
}
//실행결과
TimeInvocationHandler - TimeProxy 실행
AImpl - A 호출
TimeInvocationHandler - TimeProxy 종료 resultTime=0
- 프록시가 동적으로 만들어지고, 실행된 것을 알 수 있다.
- dynamicA -> proxy -> AImpl
📌 JDK 동적 프록시의 한계
- JDK 동적 프록시는 인터페이스가 필수이다.
- 그럼 인터페이스 없이 클래스만 있는 경우에는 어떻게 동적 프록시를 적용할 수 있을까?
- 다음 게시물에서 배울
CGLIB
라는 바이트코드를 조작하는 라이브러리를 사용해야 한다.
- 다음 게시물에서 배울
인프런의 '스프링 핵심 원리 고급편(김영한)'을 스스로 정리한 글입니다.
자세한 내용은 해당 강의를 참고해주세요.
Author And Source
이 문제에 관하여(자바 - 동적 프록시(proxy) 기술( JDK 동적 프록시)), 우리는 이곳에서 더 많은 자료를 발견하고 링크를 클릭하여 보았다 https://velog.io/@gmtmoney2357/자바-동적-프록시proxy-기술저자 귀속: 원작자 정보가 원작자 URL에 포함되어 있으며 저작권은 원작자 소유입니다.
우수한 개발자 콘텐츠 발견에 전념 (Collection and Share based on the CC Protocol.)