본문 바로가기

개인공부

Reflection 과 Jdk동적 프록시

반응형

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 종료

 

공통로직을 이쁘게 묶는 방법이 필요하다... 이럴 때 사용하는게 reflection이다.

 

        //클래스 정보
        Class classHello = Class.forName("hello.proxy.jdkdynamic.ReflectionTest$Hello");

        Hello target = new Hello();
        //callA 메서드 정보
        Method methodCallA = classHello.getMethod("callA");
        Object result1 = methodCallA.invoke(target);
        log.info("result1={}", result1);

        //callB 메서드 정보
        Method methodCallB = classHello.getMethod("callB");
        Object result2 = methodCallB.invoke(target);
        log.info("result2={}", result2);

getMethod 함수를 통해서 Method를 호출할수있다. 이때 invoke라는 메서드를 사용하게 되는데 해당 method를 콜하는 기능을  한다.

 

        //클래스 정보
        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);
    }

공통화 하기 어려울것 같았다. 공통로직을 dynamicCall이라는 메서드로 공통화 한다.

 

코드를 보면 알 수있지만 method.invoke를 통해서 함수를 호출하고 그 위 앞으로 감쌀수있는 전략을 구사할 수 있다.

한마디로.. 함수를 저장하고 나중에 호출?? 할 수 있는 방법이 생긴것..

 

이것을 생각하고 JDK 프록시를 보자.

 

먼저 InvocationHandler를 사용해야한다.

여기서는 위의 dynamicCall 같은 공통로직을 저장하는 곳이다. 이제 이 공통로직을 호출해보도록 하자.

@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;
    }
}

 

다음과 같이 Proxy.newProxyInstance를 이용해서 프록시를 생성하고 필요한 인자값을 넣어준뒤 call을 하면 

hadler에서 공통로직으로 감싼 부분은 공통로직으로 설정이 가능하다.

    @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());
    }

    @Test
    void dynamicB() {
        BInterface target = new BImpl();
        TimeInvocationHandler handler = new TimeInvocationHandler(target);

        BInterface proxy = (BInterface) Proxy.newProxyInstance(BInterface.class.getClassLoader(), new Class[]{BInterface.class}, handler);

        proxy.call();
        log.info("targetClass={}", target.getClass());
        log.info("proxyClass={}", proxy.getClass());
    }

 

실제로는 필요한 interface에 공통로직이 필요하다면 @Bean으로도 등록할 수 있다.

    @Bean
    public OrderRepositoryV1 orderRepositoryV1(LogTrace logTrace) {
        OrderRepositoryV1 orderRepository = new OrderRepositoryV1Impl();

        OrderRepositoryV1 proxy = (OrderRepositoryV1) Proxy.newProxyInstance(OrderRepositoryV1.class.getClassLoader(),
                new Class[]{OrderRepositoryV1.class},
                new LogTraceBasicHandler(orderRepository, logTrace));
        return proxy;
    }
반응형

'개인공부' 카테고리의 다른 글

DDD 공부 : 마이크로서비스  (0) 2023.06.28
인터페이스 프록시 VS 클래스 기반 프록시 패턴  (0) 2022.05.15
프록시 패턴 / 데코레이터 패턴  (0) 2022.03.28
템플릿 콜백 패턴  (0) 2022.03.28
전략 패턴  (0) 2022.03.28