동적 프록시 - (3) CGLIB

Drumj·2023년 2월 8일
0

오늘의 학습

프록시를 사용하는 프록시 패턴, 데코레이터 패턴을 배운 이후

프록시 클래스들의 소스 코드는 거의 동일한 모양을 하고 있는데 이 프록시를 적용하기 위해서
계속 프록시 클래스들을 만들어야 하는 문제점이 있었다.

동적 프록시 기술을 이용해서 쉽게 적용시켜보자!

  1. 리플렉션
  2. JDK 동적 프록시
  3. CGLIB

3. CGLIB : Code Generator LIBrary

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

참고로 우리가 CGLIB를 직접 사용하는 경우는 거의 없다고 하신다. 스프링의 ProxyFactory라는 것이 이 기술을 편하게 사용하게 도와주기 때문이라고 한다.

그러니까 간단하게 알아보도록 하자.

구체 클래스만 있는 서비스 클래스를 사용하자.


@Slf4j
public class ConcreteService {
	public void call() {
    	log.info("ConcreteService 호출");
	}
}

JDK 동적 프록시가 InvocationHandler 를 제공했듯이,
CGLIB은 MethodInterceptor를 제공한다.

@Slf4j
public class TimeMethodInterceptor implements MethodInterceptor {

	private final Object target;
    
	public TimeMethodInterceptor(Object target) {
		this.target = target;
	}
 
 	@Override
    public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable {
    	log.info("TimeProxy 실행");
        long startTime = System.currentTimeMillis();
        Object result = proxy.invoke(target, args);
        long endTime = System.currentTimeMillis();
        long resultTime = endTime - startTime;
        log.info("TimeProxy 종료 resultTime={}", resultTime);
        return result;
	}
}

ConcreteServiceTimeMethodInterceptor를 만들었다.
이제 Test Code로 CGLIB를 사용해보자.


@Test
void cglib() {
	ConcreteService target = new ConcreteService();
    
    Enhancer enhancer = new Enhancer();
    enhancer.setSuperclass(ConcreteService.class);
    enhancer.setCallback(new TimeMethodInterceptor(target));
    
    ConcreteService proxy = (ConcreteService)enhancer.create();
    
    log.info("targetClass={}", target.getClass()); //targetClass와 
    log.info("proxyClass={}", proxy.getClass()); //proxyClass를 알아보기 위해 남긴 로그
    
    proxy.call();
 }

이 코드도 마찬가지로 proxy.call()이 실제 로직이고 나머지는 설정이다.
이렇게 해서 구체 클래스에서도 동적으로 프록시를 만들어서 적용할 수 있었다.


프록시가 동작은 이해하겠는데 코드는 어렵다. 완강 후 다시 들을날을 기약하며....

0개의 댓글