본문 바로가기
Java

JDK Dynamic Proxy와 CGLIB

by J_Remind 2024. 7. 30.

JDK Dynamic Proxy와 CGLIB 모두 프록시 객체를 동적으로 만들어 낼 수 있다.

JDK Dynamic Proxy는 Java가 기본적으로 제공하는 동적 프록시 기술이며 CGLIB는 오픈소스 기술이다.

 

JDK Dynamic Proxy는 인터페이스를 구현(Implement)하고, CGLIB는 구체 클래스를 상속(extends)해서 프록시를 생성한다.

SpringBoot AOP에서는 CGLIB를 Default로 사용한다.

JDK Dynamic Proxy

인터페이스 기반으로 프록시를 동적으로 만들어 주기 때문에 인터페이스가 필수이다.

InvocationHandler 인터페이스를 구현해서 작성하면 된다.

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

}

target 은 동적 프록시가 호출할 대상으로 method.invoke(target, args) 를 통해 실행한다.

예제 코드

public interface AInterface {
     String call();
}
@Slf4j
public class AImpl implements AInterface {
    @Override
    public String call() {
       log.info("A 호출");
       return "a"; 
    }
}
@Slf4j
public class JdkDynamicProxyTest {
    @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());
    }
}

Proxy.newProxyInstance 는 동적 프록시를 생성하는 함수이며 프록시를 만들 인터페이스 클래스의 클래스 로더, 클래스 정보, 핸들러를 인자로 전달한다.

JDK Dynamic Proxy를 통해 공통의 부가 기능 로직을 하나의 클래스에 정의하며 단일 책임 원칙(SRP)를 지킬 수 있다. 하지만 인터페이스가 필수이기 때문에 인터페이스가 없이 클래스만 있는 경우 적용 할 수 없다. 이러한 문제를 해결하기 위해 CGLIB 라이브러리를 활용한다.

CGLIB

CGLIB는 바이트코드를 조작해서 동적으로 클래스를 생성하는 기술을 제공하는 라이브러리이다. 인터페이스 없는 구체 클래스만을 가지고 동적 프록시를 만들 수 있다.

주로 CGLIB를 직접 사용하지 않고 스프링의 ProxyFactory를 활용해 사용한다.

프록시 팩토리(ProxyFactory)

스프링은 동적 프록시를 통합해서 편리하게 만들어주는 프록시 팩토리라는 기능을 제공한다.

프록시 팩토리를 통해 인터페이스가 있으면 JDK 동적 프록시를 사용하고, 구체 클래스만 있다면 CGLIB를 사용한다.

 

'Java' 카테고리의 다른 글

Java Collections Framework  (0) 2020.03.25
(Java) JVM 메모리 구조  (0) 2020.03.18
(Java) 객체지향 프로그래밍  (0) 2020.03.18