JDK 6.0에서 CGLib과 JDK 프록시 성능 비교
테스트 환경
JDK 1.6
CGLib 2.1_3 nodep
Spring 2.5.5
테스트 클래스
@ContextConfiguration(locations="springContext.xml")
public class HelloAspectTest{
@Autowired
Hello goodHelloImpl;
@Test
public void createProxy() throws Exception {
assertNotNull(goodHelloImpl);
StopWatch stopWatch = new StopWatch();
testProxiedMethod(10, stopWatch);
System.out.println("total " + stopWatch.getTotalTimeMillis());
}
private void testProxiedMethod(int count, StopWatch stopWatch) {
while(count > 0){
stopWatch.start();
for(int i = 0 ; i < 1000000 ; i++)
goodHelloImpl.hi();
stopWatch.stop();
System.out.println(stopWatch.getLastTaskTimeMillis());
count--;
}
}
}
CGLib을 사용할 때는 Concrete class 타입을 써도 상관없는데, JDK 프록시를 사용할 때는 인터페이스 타입을 써야 합니다. 이유는 아시죠? 설명은 패스합니다.
StopWatch 클래스는 스프링이 제공해주는건데, 위처럼 요긴하게 쓸 수 있습니다. API는 설명이 필요 없을 만큼 작명을 잘 해뒀기 때문에 그냥 읽어보시면 어떤 일을 하는지 알 수 있으실 겁니다.
스프링 설정 파일
<context:include-filter type="annotation" expression="org.aspectj.lang.annotation.Aspect" />
</context:component-scan>
<aop:aspectj-autoproxy proxy-target-class="true" />
윗 부분에 주의해야 합니다. proxy-target-class="true" 이 설정을 삭제하면, JDK 프록시를 사용하는 것이고, 저 설정 그대로면, CGLib을 사용하는 겁니다.
어드바이스 적용 대상 인터페이스 => 타겟 인터페이스
public String hi();
}
어드바이스 적용 대상 구현체 => 타겟 클래스
public class GoodHelloImpl implements Hello {
public String hi(){
return "";
}
}
클래스 이름이나 메소드 이름 등에 너무 신경쓰지 말아주세요. 흑흑..ㅠ.ㅠ 대충 만든거란 말에요. 그것 보단, 이 녀석이 인터페이스를 구현하고 있기 때문에, 스프링이 프록시를 만들 때 proxy-target-class="true" 이 설정이 없으면 기본적으로 JDK 프록시를 생성한다는 사실.. 아시죠?
자 그럼 이제부터 쇼타임.
1. CGLib 사용시
위 설정 그대로 입니다.
1250
1204
1203
1218
1204
1203
1203
1219
1218
1219
total 12141
2. JDK 프록시 사용시
스프링 설정에서 proxy-target-class="true" 이걸 삭제합니다.
1687
1657
1656
1656
1656
1672
1672
1672
1656
1656
total 16640
3. CGLib 프록시를 서버 모드로
위 설정 그대로 사용합니다.
테스트 실행시 VM 인자에 -server 추가합니다.
813
796
797
813
797
797
812
797
797
total 8172
4. JDK 프록시를 서버 모드로
스프링 설정에서 proxy-target-class="true" 이걸 삭제합니다.
테스트 실행시 VM 인자에 -server 추가합니다.
1078
922
922
937
906
938
906
922
937
938
total 9406
캬요~ 자바지기님께서 테스트 했을 때에 비하면 JDK 프록시 성능 많이 좋아졌죠?