ひがやすを技術ブログ

電通国際情報サービスのプログラマ

DI&AOPパフォーマンス比較

明日のjava-ja@富山で、話すネタとして、DIContainerのパフォーマンス比較をしてみました。使ったのは、Spring, Guice, Seasar2.4, Slim3です。
DIのテストは、プロトタイプのBean同士のsetter injection。AOPのテストは、
何もせずにもとのメソッドを呼び出すだけの単純なものです。
使ったプロジェクトは、http://svn.slim3.org/browse/trunk/container-benchmark/においてあります。


結果はこんな感じ。
最初はDI。それぞれ10000回ループさせるテストを5回繰り返しています。


Slim3 DI: 319120167 nano
Seasar2 DI: 350858838 nano
Guice DI: 283541623 nano
Spring DI: 657129328 nano

      • -

Slim3 DI: 9310960 nano
Seasar2 DI: 156790598 nano
Guice DI: 35546697 nano
Spring DI: 356141353 nano

      • -

Slim3 DI: 9703748 nano
Seasar2 DI: 162930484 nano
Guice DI: 34984055 nano
Spring DI: 356262598 nano

      • -

Slim3 DI: 9500369 nano
Seasar2 DI: 157047893 nano
Guice DI: 34867001 nano
Spring DI: 343818558 nano

      • -

Slim3 DI: 9456230 nano
Seasar2 DI: 146980971 nano
Guice DI: 35360918 nano
Spring DI: 344662520 nano

      • -

Slim3は、最初だけ遅いですが、後は速いですね。GuiceSlim3には負けてますが、Seasar2やSpringよりも速い。Seasar2とSpringの差は2倍。まぁ、こんなもんでしょう。


次はAOP。それぞれ10000回ループさせるテストを5回繰り返しています。


Slim3 AOP: 20136917 nano
Seasar2 AOP: 6659785 nano
Guice AOP: 18718301 nano
Spring AOP: 65014129 nano

        • -

Slim3 AOP: 12302681 nano
Seasar2 AOP: 4772394 nano
Guice AOP: 6979937 nano
Spring AOP: 6276496 nano

        • -

Slim3 AOP: 6722642 nano
Seasar2 AOP: 4946438 nano
Guice AOP: 5509080 nano
Spring AOP: 7828369 nano

        • -

Slim3 AOP: 6590782 nano
Seasar2 AOP: 4869613 nano
Guice AOP: 5534781 nano
Spring AOP: 7270477 nano

        • -

Slim3 AOP: 1656355 nano
Seasar2 AOP: 3323328 nano
Guice AOP: 6633525 nano
Spring AOP: 6093791 nano

        • -

Seasar2AOPは、カリカリにチューニングされているだけあって、安定して速い。ただし、二回目以降は、それほどは差がついてません。
Slim3は、回数が増すごとにだんだん速くなってますね。さっきのDIも。理由は良くわかりません。コードが単純なので、VMが最適化しやすいのかもしれません。


明日は、これらの結果を踏まえて、ソースを見ながら、さらにAOPの実装の違いに触れます。東京ではやらないような濃いネタですが、こじんまりとした会だし、たまにはこういうのも楽しいでしょう。
最後に、それぞれのテストコードをのせて起きます。

package benchmark.main;

import org.seasar.framework.container.ComponentDef;
import org.seasar.framework.container.PropertyDef;
import org.seasar.framework.container.S2Container;
import org.seasar.framework.container.deployer.InstanceDefFactory;
import org.seasar.framework.container.impl.ComponentDefImpl;
import org.seasar.framework.container.impl.PropertyDefImpl;
import org.seasar.framework.container.impl.S2ContainerImpl;
import org.slim3.container.S3Container;
import org.springframework.beans.MutablePropertyValues;
import org.springframework.beans.factory.config.RuntimeBeanReference;
import org.springframework.beans.factory.support.DefaultListableBeanFactory;
import org.springframework.beans.factory.support.RootBeanDefinition;

import benchmark.action.FooAction;
import benchmark.service.BarService;

import com.google.inject.Guice;
import com.google.inject.Injector;

public class DIMain {

    private static final int COUNT = 10000;

    public static void main(String[] args) {
        for (int i = 0; i < 5; i++) {
            slim3();
            seasar2();
            guice();
            spring();
            System.out.println("----");
        }
    }

    private static void slim3() {
        S3Container container = new S3Container();
        long start = System.nanoTime();
        for (int i = 0; i < COUNT; i++) {
            container.lookup(FooAction.class);
        }
        System.out.printf("Slim3   DI:%10d nano\n", System.nanoTime() - start);
    }

    private static void seasar2() {
        S2Container container = new S2ContainerImpl();
        ComponentDef cd = new ComponentDefImpl(FooAction.class, "fooAction");
        cd.setInstanceDef(InstanceDefFactory.PROTOTYPE);
        PropertyDef pd = new PropertyDefImpl("barService");
        cd.addPropertyDef(pd);
        ComponentDef cd2 = new ComponentDefImpl(BarService.class, "barService");
        cd2.setInstanceDef(InstanceDefFactory.PROTOTYPE);
        container.register(cd);
        container.register(cd2);
        long start = System.nanoTime();
        for (int i = 0; i < COUNT; i++) {
            container.getComponent(FooAction.class);
        }
        System.out.printf("Seasar2 DI:%10d nano\n", System.nanoTime() - start);
    }

    private static void guice() {
        Injector injector = Guice.createInjector();
        long start = System.nanoTime();
        for (int i = 0; i < COUNT; i++) {
            injector.getInstance(FooAction.class);
        }
        System.out.printf("Guice   DI:%10d nano\n", System.nanoTime() - start);
    }

    private static void spring() {
        DefaultListableBeanFactory beanFactory = new DefaultListableBeanFactory();

        RootBeanDefinition fooDef = new RootBeanDefinition(FooAction.class);
        fooDef.setScope("prototype");
        MutablePropertyValues fooValues = new MutablePropertyValues();
        fooValues.addPropertyValue("barService", new RuntimeBeanReference(
                "barService"));
        fooDef.setPropertyValues(fooValues);
        beanFactory.registerBeanDefinition("fooAction", fooDef);
        RootBeanDefinition barDef = new RootBeanDefinition(BarService.class);
        barDef.setScope("prototype");
        beanFactory.registerBeanDefinition("barService", barDef);
        long start = System.nanoTime();
        for (int i = 0; i < COUNT; i++) {
            beanFactory.getBean("fooAction");
        }
        System.out.printf("Spring  DI:%10d nano\n", System.nanoTime() - start);
    }
}
package benchmark.main;

import static com.google.inject.matcher.Matchers.*;

import org.seasar.framework.aop.impl.PointcutImpl;
import org.seasar.framework.container.AspectDef;
import org.seasar.framework.container.ComponentDef;
import org.seasar.framework.container.S2Container;
import org.seasar.framework.container.deployer.InstanceDefFactory;
import org.seasar.framework.container.impl.AspectDefImpl;
import org.seasar.framework.container.impl.ComponentDefImpl;
import org.seasar.framework.container.impl.S2ContainerImpl;
import org.slim3.container.S3Container;
import org.springframework.aop.framework.ProxyFactoryBean;
import org.springframework.beans.MutablePropertyValues;
import org.springframework.beans.factory.support.DefaultListableBeanFactory;
import org.springframework.beans.factory.support.RootBeanDefinition;

import benchmark.interceptor.SimpleInterceptor;
import benchmark.service.Aop2Service;
import benchmark.service.AopService;

import com.google.inject.AbstractModule;
import com.google.inject.Guice;
import com.google.inject.Injector;

public class AOPMain {

    private static final int COUNT = 10000;

    public static void main(String[] args) throws Exception {
        for (int i = 0; i < 5; i++) {
            slim3();
            seasar2();
            guice();
            spring();
            System.out.println("-----");
        }
    }

    private static void slim3() {
        S3Container container = new S3Container();
        AopService service = container.lookup("aopService");
        long start = System.nanoTime();
        for (int i = 0; i < COUNT; i++) {
            service.aaa();
        }
        System.out.printf("Slim3   AOP:%10d nano\n", System.nanoTime() - start);
    }

    private static void seasar2() throws Exception {
        S2Container container = new S2ContainerImpl();
        ComponentDef cd = new ComponentDefImpl(AopService.class, "barService");
        cd.setInstanceDef(InstanceDefFactory.PROTOTYPE);
        AspectDef ad = new AspectDefImpl(new SimpleInterceptor(),
                new PointcutImpl(new String[] { "aaa" }));
        cd.addAspectDef(ad);
        container.register(cd);
        AopService service = (AopService) container
                .getComponent(AopService.class);
        long start = System.nanoTime();
        for (int i = 0; i < COUNT; i++) {
            service.aaa();
        }
        System.out.printf("Seasar2 AOP:%10d nano\n", System.nanoTime() - start);
    }

    private static void guice() {
        Injector injector = Guice.createInjector(new AbstractModule() {
            protected void configure() {
                bindInterceptor(only(Aop2Service.class), any(),
                        new SimpleInterceptor());
            }
        });
        Aop2Service service = injector.getInstance(Aop2Service.class);
        long start = System.nanoTime();
        for (int i = 0; i < COUNT; i++) {
            service.aaa();
        }
        System.out.printf("Guice   AOP:%10d nano\n", System.nanoTime() - start);
    }

    private static void spring() {
        DefaultListableBeanFactory beanFactory = new DefaultListableBeanFactory();
        RootBeanDefinition serviceDef = new RootBeanDefinition(AopService.class);
        beanFactory.registerBeanDefinition("aopService", serviceDef);

        RootBeanDefinition interceptorDef = new RootBeanDefinition(
                SimpleInterceptor.class);
        beanFactory.registerBeanDefinition("simpleInterceptor", interceptorDef);
        RootBeanDefinition proxyDef = new RootBeanDefinition(
                ProxyFactoryBean.class);
        proxyDef.setScope("prototype");
        MutablePropertyValues proxyValues = new MutablePropertyValues();
        proxyValues.addPropertyValue("target", serviceDef);
        proxyValues.addPropertyValue("interceptorNames",
                new String[] { "simpleInterceptor" });
        proxyDef.setPropertyValues(proxyValues);
        beanFactory.registerBeanDefinition("proxy", proxyDef);
        AopService service = (AopService) beanFactory.getBean("proxy");
        long start = System.nanoTime();
        for (int i = 0; i < COUNT; i++) {
            service.aaa();
        }
        System.out.printf("Spring  AOP:%10d nano\n", System.nanoTime() - start);
    }
}