// Spring 에서 제공하는 프록시 팩토리 기능 적용 start Objectresult= invocation.proceed(); // Spring 에서 제공하는 프록시 팩토리 기능 적용 end
longendTime= System.currentTimeMillis();
longresultTime= endTime - startTime; log.info("TimeProxy 종료 resultTime = {}", resultTime);
return result; } }
프록시 객체에 Advice(부가 기능) 적용
ProxyFactory 를 이용해 프록시 객체를 생성합니다. ProxyFactory 는 전달받은 인스턴스 정보를 기반으로 프록시 객체를 생성합니다. 인터페이스가 있는 객체인 경우 JDK 동적 프록시 를 사용해 프록시 객체를 생성하고 인터페이스가 없을 경우에는 CGLIB 를 사용해 프록시 객체를 생성합니다.
생성된 프록시 객체에 addAdvice 메소드를 이용해 부가 기능을 위한 Advice 를 추가한다.
// 인터페이스가 있으면 동적 프록시 사용
ServiceInterfacetarget=newServiceImpl();
// ProxyFactory 를 생성할 때 프록시 호출 대상을 인자로 넘겨준다. ProxyFactoryproxyFactory=newProxyFactory(target);
// ProxyFactory 객체에 부가 기능을 위한 Advice 정보를 추가한다. proxyFactory.addAdvice(newTimeAdvice());
ProxyFactory 객체는 JDK Dynamic Proxy 를 기반으로 만들어진 것을 확인할 수 있다.
21:33:13.233 [Test worker] INFO hello.proxy.proxyfactory.ProxyFactoryTest - targetClass = class hello.proxy.common.service.ServiceImpl 21:33:13.237 [Test worker] INFO hello.proxy.proxyfactory.ProxyFactoryTest - proxyClass = class com.sun.proxy.$Proxy13 21:33:13.242 [Test worker] INFO hello.proxy.common.advice.TimeAdvice - TimeProxy 실행 21:33:13.243 [Test worker] INFO hello.proxy.common.service.ServiceImpl - save 호출 21:33:13.243 [Test worker] INFO hello.proxy.common.advice.TimeAdvice - TimeProxy 종료 resultTime = 1
프록시 적용 확인
테스트에서 ProxyFactory 를 통해 Proxy 객체가 생성됐는지 확인하고 Advice (부가기능) 로직을 수행하는지 확인합니다.
프록시 객체 생성시 인터페이스가 있는 객체일 경우 JDK Dynamic Proxy 를 이용해 프록시 객체를 생성됐는지 확인하고, 인터페이스가 없는 객체일 경우 CGLIB 를 이용해 프록시 객체를 생성했는지 확인합니다.
Jdk Dynamic Proxy 를 이용한 Proxy 생성 확인
ProxyFactory 를 이용해 프록시를 생성할 때 인터페이스가 있으면 JDK Dynamic Proxy 를 이용해 동적 프록시를 생성한다.
// Proxy Factory 를 이용해 만들었을 때 사용가능 assertThat(AopUtils.isAopProxy(proxy)).isTrue(); // AopProxy 를 이용해 동적 프록시를 생성했는지 확인 assertThat(AopUtils.isJdkDynamicProxy(proxy)).isTrue(); // JdkDynamicProxy 를 이용해 동적 프록시를 생성했는지 확인 assertThat(AopUtils.isCglibProxy(proxy)).isFalse(); // CglibProxy 를 이용해 동적 프록시를 생성했는지 확인
com.sun.proxy.Proxy13 를 통해 JdkDynamicProxy 를 이용해 동적 프록시가 생성 된 것을 확인할 수 있다.
23:00:05.128 [Test worker] INFO hello.proxy.proxyfactory.ProxyFactoryTest - targetClass = class hello.proxy.common.service.ServiceImpl 23:00:05.132 [Test worker] INFO hello.proxy.proxyfactory.ProxyFactoryTest - proxyClass = class com.sun.proxy.$Proxy13 23:00:05.136 [Test worker] INFO hello.proxy.common.advice.TimeAdvice - TimeProxy 실행 23:00:05.136 [Test worker] INFO hello.proxy.common.service.ServiceImpl - save 호출 23:00:05.136 [Test worker] INFO hello.proxy.common.advice.TimeAdvice - TimeProxy 종료 resultTime = 0
// Proxy Factory 를 이용해 만들었을 때 사용가능 assertThat(AopUtils.isAopProxy(proxy)).isTrue(); assertThat(AopUtils.isJdkDynamicProxy(proxy)).isFalse(); assertThat(AopUtils.isCglibProxy(proxy)).isTrue();
EnhancerBySpringCGLIB 를 통해 CGLIB 를 이용해 동적 프록시가 생성됐는지 확인할 수 있다.
21:50:00.561 [Test worker] INFO hello.proxy.proxyfactory.ProxyFactoryTest - targetClass = class hello.proxy.common.service.ConcreteService 21:50:00.563 [Test worker] INFO hello.proxy.proxyfactory.ProxyFactoryTest - proxyClass = class hello.proxy.common.service.ConcreteService$$EnhancerBySpringCGLIB$$8328efc5 21:50:00.565 [Test worker] INFO hello.proxy.common.advice.TimeAdvice - TimeProxy 실행 21:50:00.576 [Test worker] INFO hello.proxy.common.service.ConcreteService - ConcreteService 호출 21:50:00.576 [Test worker] INFO hello.proxy.common.advice.TimeAdvice - TimeProxy 종료 resultTime = 10
CGLIB 를 이용한 강제 Proxy 생성 확인
ProxyFactory 가 프록시 객체 생성시 인터페이스가 있는 객체더라도 CGLIB 를 이용해 프록시 객체를 생성할 수 있습니다.
ProxyFactory 클래스에서 제공하는 setProxyTargetClass 메소드에 true 값을 넣으면 프록시 객체 생성시 CGLIB 를 이용해 프록시 객체를 생성합니다.
// ProxyTargetClass 옵션을 사용하면 인터페이스가 있어도 CGLIB를 사용하고, 클래스 기반 프록시 사용
ConcreteServicetarget=newConcreteService(); ProxyFactoryproxyFactory=newProxyFactory(target); proxyFactory.setProxyTargetClass(true); // 이 옵션이 있으면 항상 CGLIB 를 사용해 프록시를 생성한다. proxyFactory.addAdvice(newTimeAdvice()); ConcreteServiceproxy= (ConcreteService) proxyFactory.getProxy();
// Proxy Factory 를 이용해 만들었을 때 사용가능 assertThat(AopUtils.isAopProxy(proxy)).isTrue(); assertThat(AopUtils.isJdkDynamicProxy(proxy)).isFalse(); assertThat(AopUtils.isCglibProxy(proxy)).isTrue();
EnhancerBySpringCGLIB 를 통해 setProxyTargetClass 메소드를 이용해 CGLIB 를 사용한 프록시 생성을 강제할 수 있음을 확인할 수 있다.
22:14:06.412 [Test worker] INFO hello.proxy.proxyfactory.ProxyFactoryTest - targetClass = class hello.proxy.common.service.ConcreteService 22:14:06.414 [Test worker] INFO hello.proxy.proxyfactory.ProxyFactoryTest - proxyClass = class hello.proxy.common.service.ConcreteService$$EnhancerBySpringCGLIB$$116d9156 22:14:06.416 [Test worker] INFO hello.proxy.common.advice.TimeAdvice - TimeProxy 실행 22:14:06.427 [Test worker] INFO hello.proxy.common.service.ConcreteService - ConcreteService 호출 22:14:06.427 [Test worker] INFO hello.proxy.common.advice.TimeAdvice - TimeProxy 종료 resultTime = 10