[Spring]동적 프록시

Hyunho·2021년 11월 25일
0

동적 프록시

Java가 기본으로 제공하는.JDK동적 프록시 기술이나 CGLIB같은 프록시 생성 오픈소스 기술을 활용하면 프록시 객체를 동적으로 만들어낼 수 있다.
프록시를 적용할 코드를 하나만 만들어두고 동적 프록시 기술을 사용해서 프록시 객체를 만들면 된다.

JDK동적 프록시

jdk동적 프록시는 인터페이스를 기반으로 프록시를 동적으로 만들어준다. 따라서 인터페이스가 필수

JDK독적 프록시 예제

  • Interface
public interface AInterface {
    String call();
}
  • 구체 class
@Slf4j
public class AImpl implements AInterface{
    @Override
    public String call() {
        log.info("A 호출");
        return "a";
    }
}
  • 동적 프록시에 적용할 핸들러 로직
@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); //target의 method를 실행
        long endTime = System.currentTimeMillis();
        long resultTime = endTime - startTime;
        log.info("TimeProxy 종료 resultTime={}", resultTime);
        return result;
    }
}
  • test
@Test
void dynamicA() {
    AInterface target = new AImpl();
    TimeInvocationHandler handler = new TimeInvocationHandler(target);

    //proxy 생성 - Proxy.newProxyInstance(어디에 생성될지, 들어가는 인터페이스(어떤 인터페이스를 기반으로 프록시를 만들지), 프록시가 사용할 로직 호출)
    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());
}
  • Proxy.newProxyInstance(A, B, C) - proxy 생성
    • A - 클래스 로더 정보
    • B - 인터페이스(어떤 인터페이스를 기반으로 프록시를 만들지)
    • C - 프록시가 사용할 로직 호출
  • 실행 순서
    • JDK동적 프록시의 call() 실행
    • JDK동적 프로시는 InvocationHandler.invoke() 를 호출. TimeInvocationHandler가 구현체로 있으므로 TimeInvocationHandler.invoke()가 호출 됨
    • TimeInvocationHandler 가 내부적으로 수행하고 method.invoke(target, args) 를 호출해서 target인 실제 객체 AImpl 을 호출
    • AImpl인스턴스의 call()실행
    • AImpl인스턴스의 call()실행이 끝나면 TimeInvocationHandler로 응답이돈다
스크린샷 2021-11-25 오후 3 58 19
profile
hyunho

0개의 댓글