JDK 동적 프록시는 Java의 내장 기능으로, 특정 인터페이스를 구현한 클래스의 메서드 호출을 중간에서 가로채서 추가적인 작업을 수행하게 해준다. 이를 위해 InvocationHandler 인터페이스를 구현해야 하며, 이 때 중요한 메서드는 invoke()이다.

 

public interface AInterface {
    void callA();
}

public class AImpl implements AInterface {
    @Override
    public void callA() {
        System.out.println("AImpl callA");
    }
}
public interface BInterface {
    void callB();
}

public class BImpl implements BInterface {
    @Override
    public void callB() {
        System.out.println("BImpl callB");
    }
}

다음과 같은 인터페이스와 구현체가 주어진 상황에서, InvocationHandler를 구현한 클래스를 생성하여 로직을 공통화한다.

public class TimeInvocationHandler implements InvocationHandler {
    private Object target;

    public TimeInvocationHandler(Object target) {
        this.target = target;
    }

    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        long start = System.currentTimeMillis();
        Object result = method.invoke(target, args);
        long end = System.currentTimeMillis();
        System.out.println(method.getName() + " executed in " + (end - start) + "ms");
        return result;
    }
}

이후에 Proxy.newProxyInstance를 이용해 AInterface와 BInterface에 대해 공통 로직을 적용하여 실행할 수 있다.

 

@Test
void jdkDynamicProxyTest() {
    // AInterface에 대한 프록시 객체 생성
    AInterface aProxy = (AInterface) Proxy.newProxyInstance(AInterface.class.getClassLoader(),
            new Class[]{AInterface.class},
            new TimeInvocationHandler(new AImpl()));
    
    // 프록시 객체를 통한 메서드 호출
    aProxy.callA();

    // BInterface에 대한 프록시 객체 생성
    BInterface bProxy = (BInterface) Proxy.newProxyInstance(BInterface.class.getClassLoader(),
            new Class[]{BInterface.class},
            new TimeInvocationHandler(new BImpl()));
    
    // 프록시 객체를 통한 메서드 호출
    bProxy.callB();
}

 

여기서 Proxy.newProxyInstance()의 인자는 총 3가지다. 첫번째 인자는 ClassLoader를 의미한다. 이는 JVM에 클래스를 로드하는 방식을 정의하는 것으로, 읽을 범위나 방법을 결정한다. 두번째 인자는 프록시가 구현해야 할 대상 인터페이스들의 배열이다. 세번째 인자는 InvocationHandler를 구현한 객체로, 공통 로직이 담겨있다.

결론적으로 Proxy.newProxyInstance() 메서드는 (로드 방식, 대상 인터페이스, 로직)의 3가지 인자를 받는다.

 

 

'Java > 스프링 AOP' 카테고리의 다른 글

ProxyFactory (1) CGLIB, JDK 동적 프록시  (0) 2023.08.20
CGLIB  (0) 2023.08.19
리플렉션  (0) 2023.08.16
구체클레스, 인터페이스 프록시  (0) 2023.08.15
서브쿼리, JOIN, 프로시저  (0) 2023.08.08

+ Recent posts