Spring

[Spring Boot] JDK Proxy vs CGLIB Proxy

Joo.v7 2024. 11. 24. 11:06

(좌) JDK Proxy / (우) CGLib Proxy

JDK Proxy

  • 인터페이스 기반 프록시
  • JDK Proxy는 자바 리플렉션과 인터페이스를 기반으로 프록시 객체를 생성한다. 따라서 대상 객체가 반드시 인터페이스를 구현해야 한다.
  • 리플렉션 사용.
더보기

Proxy.newProxyInstance를 보면 Reflection을 사용하고 있다.

InvocationHandler를 구현해서 사용.

public class JdkGreeting implements Greeting {

    Greeting proxy;

    public JdkGreeting(KoreanGreeting koreanGreeting) {
        proxy = (Greeting) Proxy.newProxyInstance(Greeting.class.getClassLoader(),
                                                  new Class[]{Greeting.class},
                                                  new GreetingProxyHandler(koreanGreeting));
    }

    public static class GreetingProxyHandler implements InvocationHandler {

        private final Object target;

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

        @Override
        public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {

            StopWatch stopWatch = new StopWatch("greeting time");
            stopWatch.start();

            Object result = method.invoke(target, args);

            stopWatch.stop();
            System.out.println(stopWatch.prettyPrint());

            return result;
        }
    }

    @Override
    public void sayHello() {
        proxy.sayHello();
    }
}

 

CGLIB Proxy

  • 상속 기반 프록시
  • CGLIB Proxy는 바이트 코드 조작을 이용하여, 대상 객체의 서브 클래스를 생성한다. 이는 대상 객체가 인터페이스를 구현하지 않아도 된다.
더보기

MethodInterceptor를 구현해서 사용.

public class CglibGreeting implements Greeting {

    Greeting proxy;

    public CglibGreeting(EnglishGreeting englishGreeting) {
        Enhancer enhancer = new Enhancer();
        enhancer.setSuperclass(EnglishGreeting.class);
        enhancer.setCallback(new GreetingInterceptor(englishGreeting));
        proxy = (Greeting) enhancer.create();
    }

    public static class GreetingInterceptor implements MethodInterceptor {

        private final Object target;

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

        @Override
        public Object intercept(Object obj, Method method, Object[] args, MethodProxy methodProxy) throws Throwable {
            StopWatch stopWatch = new StopWatch("greeting time");
            stopWatch.start();

            Object result = methodProxy.invoke(target, args);

            stopWatch.stop();
            System.out.println(stopWatch.prettyPrint());
            return result;
        }
    }

    @Override
    public void sayHello() {
        proxy.sayHello();
    }
}