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; }
一方GuiceのAOP設定は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は意味が無いので省略