Spring adv 05 - CGLIB
CGLIB
CGLIB(Code Generator Library)는 코드 생성 라이브러리로서 런타임에 동적으로 자바 클래스의 프록시를 생성해주는 기능을 제공한다. 인터페이스가 아닌 클래스에 대해서 동적 프록시를 생성할 수 있다. 인터페이스 기반은 JDK Dynamic Proxy로 클래스 기반은 CGLIB를 사용한다. CGLIB는 타겟에 대한 정보를 직접적으로 제공 받아 바이트 코드를 조작하여 프록시를 생성한다. 때문에 리플렉션을 사용하는 JDK Dynamic Proxy에 비해서 성능이 좋다. 또한 CGLIB는 메소드가 처음 호출 되었을 때 동적으로 타켓 클래스의 바이트 코드를 조작하고, 이후 호출 시엔 조작된 바이트 코드를 재사용한다.
- 인터페이스 없이 단순 클래스만으로 프록시 객체를 동적으로 생성이 가능하다.
- 리플렉션이 아닌 바이트 조작을 사용하며, 타겟에 대한 정보를 알고 있기 때문에 JDK Dynamic Proxy에 비해 성능이 좋다.
- TimeMethodInterceptor는 MethodInterceptor 인터페이스를 구현해서 CGLIB 프록시의 실행 로직을 정의한다.
- JDK 동적 프록시라고 생각하면 편하다
- method.invoke(target, args) 실제 대상을 동적으로 호출한다.
- ConcreteService를 상속받아서 동적으로 프록시를 만들게 된다.
- 따라서 proxy는 ConcreteService로 캐스팅이 가능하다.
- Enhancer: CGLIB는 Enhancer를 사용해서 프록시를 생성한다.
- CGLIB는 구체 클래스를 상속 받아서 프록시를 생성할 수 있다. 어떤 구체 클래스를 상속 받을지 지정한다.
- 프록시에 적용할 실행 로직을 할당한다.
- 프록시를 생성한다. 앞서 설정한 enhancer.setSuperclass(ConcreteServlce.class)에서 지정한 클래스를 상속 받아서 프록시가 만들어진다.
- 테스트 결과는 동적으로 프록시를 만들게 되는데 ConcreteService를 상속받아서 클래스를 만들게 된다.
클래스 의존 관계
여기서 Client는 TestCode를 의미한다. 우선 동적 프록시는 ConcreteServlce를 상속받아서 만들어진다. 그리고 동적 프록시는 handlerInterceptor를 뒤에서 호출하게 된다.
런타임 의존 괸계
런타임에서는 클라이언트가 cglib에게 메시지를 보내게 되고, 프록시는 timeMethodInterceptor(MethodInterceptor를 상속받은 구현체)에게 메시지를 보내게 된다. 그리고 timeMethodInterceptor는 ConcreteService의 target을 호출하게 된다.
Reference
김영한님의 스프링 핵심 원리
나의 뇌