Google Guice(その6) AOP使用時のパフォーマンス比較

※下記はコードが間違っていて訂正したので、その8をご参照下さい。
その5でid:shot6さんにコメントを頂いた事もあり、AOP使用時のパフォーマンスを比較してみます。

使うのは、Guice付属のパフォーマンス比較コードにAOP設定とAOPを挟んだメソッドの呼び出しを追加したものです。
SpringのAOPはとりあえずノーマルなProxyで。

    // 設定
    RootBeanDefinition proxy = new RootBeanDefinition(ProxyFactoryBean.class);
    MutablePropertyValues proxyValues = new MutablePropertyValues();
    proxyValues.addPropertyValue("target", new RuntimeBeanReference("barImpl"));
    proxyValues.addPropertyValue("interceptorNames", new String[]{"dummyInterceptor"});
    proxy.setPropertyValues(proxyValues);
    //...
    beanFactory.registerBeanDefinition("barImpl", bar);
    beanFactory.registerBeanDefinition("bar", proxy);
    // 実行
    public Foo call() throws Exception {
      Foo foo = (Foo) beanFactory.getBean("foo");
      foo.bar.getTee();
      return foo;
    }

一方GuiceAOP設定は1行。比較すると簡単さが際立ちます。難しい事をしようとするとまたどうなるか分からないですが、今回のようなシンプルな目的は十分果たせています。

    // 設定
    bindInterceptor(only(BarImpl.class), any(), new DummyInterceptor());
    // 実行
    public Foo call() throws Exception {
      Foo foo = fooProvider.get();
      foo.bar.getTee();
      return foo;
    }

で、実行。*1

Spring: 9,667 creations/s
Guice: 36,791 creations/s

残念ながら(?)、速度差が4倍まで縮まってしまいました。
ちなみにスタックトレースは以下のようになっています。
まずSpring。

PerformanceComparison$BarImpl.getTee() line: 241	
NativeMethodAccessorImpl.invoke0(Method, Object, Object) line: not available [native method]	
NativeMethodAccessorImpl.invoke(Object, Object) line: not available	
DelegatingMethodAccessorImpl.invoke(Object, Object) line: not available	
Method.invoke(Object, Object...) line: not available	
AopUtils.invokeJoinpointUsingReflection(Object, Method, Object) line: 299	
ReflectiveMethodInvocation.invokeJoinpoint() line: 172	
ReflectiveMethodInvocation.proceed() line: 139	
DummyInterceptor.invoke(MethodInvocation) line: 10	
ReflectiveMethodInvocation.proceed() line: 161	
JdkDynamicAopProxy.invoke(Object, Method, Object) line: 202	
$Proxy9.getTee() line: not available	
PerformanceComparison.validate(Callable) line: 176	
PerformanceComparison.main(String) line: 59	

そしてGuice

PerformanceComparison$BarImpl$$EnhancerByGuice$$75f524cf(PerformanceComparison$BarImpl).getTee() line: 241	
PerformanceComparison$BarImpl$$EnhancerByGuice$$75f524cf.CGLIB$getTee$0() line: not available	
PerformanceComparison$BarImpl$$EnhancerByGuice$$75f524cf$$FastClassByCGLIB$$265a007f.invoke(int, Object, Object) line: not available	
MethodProxy.invokeSuper(Object, Object) line: 167	
InterceptorStackCallback$InterceptedMethodInvocation.proceed() line: 67	
DummyInterceptor.invoke(MethodInvocation) line: 10	
InterceptorStackCallback$InterceptedMethodInvocation.proceed() line: 68	
InterceptorStackCallback.intercept(Object, Method, Object, MethodProxy) line: 46	
PerformanceComparison$BarImpl$$EnhancerByGuice$$75f524cf.getTee() line: not available	
PerformanceComparison.validate(Callable) line: 176	
PerformanceComparison.main(String) line: 60	

CGLIBでエンハンスされているのがよく分かります。

ところでmanholeさんがseasar2を含めて比較されてました。うーん、こちらだとちゃんと100倍出ていますね…。何が原因か分かりませんが、単なるFUDではなかったという事でcrazybobさんに心からごめんなさい。

*1:By Handは意味が無いので省略