论坛首页 Java企业应用论坛

IoC容器的prototype性能测试

浏览 23780 次
该帖已经被评为精华帖
作者 正文
   发表时间:2005-12-17  
刚刚写好。这篇文章没有介绍实现方法,只介绍最终结果。大家对照着英文的看罢。
http://www.iteye.com/pages/viewpage.action?pageId=559

对比spring2.0的侵入性方案(要求依赖容器的annotation),大家觉得哪个好呢?
   发表时间:2005-12-22  
我看了你的blog,

我自己的框架是这么做的:

package test.component;

public class Girl {
  Kissable boy;
 
/**
  * CDI
  *@@InjectAttribute()
  */
  public Girl(Kissable boy) {
    this.boy = boy;
  }

/**
  * or SDI
  *@@InjectAttribute()
  */
  public setBoy(Kissable boy) {
    this.boy = boy;
  }


  public void kissSomeone() {
    boy.kiss(this);
  }

}

配置:
<container>
  <components>
    <component key="test.model.Kissable" class="test.model.Boy"/>
    <component key="test.model.Girl" class="test.model.Girl"/>
  </components>
</container>

that's it!



我用了jakarta commons attributes,就可以让Girl和annontation class没有直接的依赖关系。

握手~~~

想到一处去了。

不过我的意见,入侵性的大小并非是判断容器好坏的标准,实用才是最重要的. 而且不同的应用场合,对容器要求还不一样. Spring对singleton的bean instantiating(性能)很出色,可是singleton=false,就完蛋了. 所以Spring不适合我自己碰到的一些应用场合. 所以自己造轮子咯. 在我的应用场合中,用annontation这种方法最好,半入侵. 更甚者, 在有些时侯convention 就该over configuration.
1 请登录后投票
   发表时间:2005-12-22  
引用
可是singleton=false,就完蛋了

为什么?spring支持prototype的呀。
1 请登录后投票
   发表时间:2005-12-22  
ajoo 写道
引用
可是singleton=false,就完蛋了

为什么?spring支持prototype的呀。


spring instantiating prototype 类型的bean效率很低, 创建prototype的BeanProxy效率更低
0 请登录后投票
   发表时间:2005-12-24  
可是。application context一般不是让你重复地getBean()用的阿。

理想情况应该是你getBean()一次或者几次,获得系统运行的必要的几个对象网,然后就洒有纳拉了。这时候prototype是否效率高很重要么?
0 请登录后投票
   发表时间:2005-12-30  
ajoo 写道
可是。application context一般不是让你重复地getBean()用的阿。

理想情况应该是你getBean()一次或者几次,获得系统运行的必要的几个对象网,然后就洒有纳拉了。这时候prototype是否效率高很重要么?


这个话题的起因应该是从Spring2的哪个post-instantiating 的blog开始的把?
里面提到了充血的domain object, 比如哪个Customer对象,需要inject DAO, 而更甚者, 在我的应用中,可能会在Customer上weave aspects来补充一些业务逻辑).

在Web层, Action调用Container instantiating 这些domain objects,然后放入context,让界面层去render. 

这个customer是有状态的吧? 如果用Spring的话,配置是否需要prototype?

在压力测试的时候, 上n百个用户并发访问这个web page, 这时候instantiating效率难道不重要么?
0 请登录后投票
   发表时间:2005-12-31  
有时间给俺的Nuts作一下benchmark,看看效率如何?


其实最近一个同志跟我讨论了另外一个应用场景:request handler。

伪码如下:
Object handleRequest(String reqid, Map parameters);{
  Service service = (Service);container.getInstance(reqid);;
  service.invoke(parameters);;
}

这个invoke()利用容器的注射能力把parameters里面的值注射到对应的java bean property里面去。


配置文件长成这样:
<function id="generic_service" params="methodname">
  <function params="parameters">
    <method name="$methodname" args="">
      <bean class="RequestHandler" props="$parameters"/>
    </method>
  </function>
</function>


<call id="req1" function="$generic_service"
       params="onRequest1"/>
<call id="req2" function="$generic_service"
       params="onRequest2"/>
...


正式的java调用代码如下:
Object handleRequest(String reqid, Map parameters);{
  Component service = container.getComponent(reqid);;
  if(service==null);
    throw new IllegalArgumentException("request handler not found");;
  return container.instantiateComponent(
    service.withArgument(0, Components.value(parameters););
  );;
}


这时候,也需要每次request都调用容器。效率应该也是一个需要考虑的问题。
0 请登录后投票
   发表时间:2005-12-31  
:idea:  先上我的benchmark result




Srping配置文件:
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE beans PUBLIC "-//SPRING//DTD BEAN//EN" "http://www.springframework.org/dtd/spring-beans.dtd">

<beans>
  
  <bean id="foo" class="test.model.FooImpl" singleton="false">
    <constructor-arg><ref bean="bar"/></constructor-arg>
  </bean>
  <bean id="bar" class="test.model.Bar" singleton="false">
  </bean>
  <bean id="soo" class="test.model.Soo" singleton="false">
    <property name="bar"><ref bean="bar"/></property>
  </bean>
  
  <bean id="fooInterceptor" class="test.interceptor.FooInterceptor" singleton="true">
  </bean>
  
  <bean id="statefulBarInterceptor" class="test.interceptor.ConcretBarInterceptorA" singleton="false">
  </bean>
  
  <bean id="fooAdvisor" 
    class="org.springframework.aop.support.RegexpMethodPointcutAdvisor">
    <property name="advice">
        <ref local="fooInterceptor"/>
    </property>
    <property name="patterns">
        <list>
            <value>.*.noop</value>
        </list>
    </property>
  </bean>
  
  <bean id="fooProxy" 
    class="org.springframework.aop.framework.ProxyFactoryBean">
    <property name="proxyInterfaces"><value>test.model.Foo</value></property>

    <property name="target"><ref local="foo"/></property>
    <property name="proxyTargetClass"><value>true</value></property>
    <property name="optimize"><value>true</value></property>
    <property name="frozen"><value>true</value></property>
    <property name="interceptorNames">
        <list>
            <value>fooAdvisor</value>
        </list>
    </property>
  </bean>
  
  <bean id="sooProxy" 
    class="org.springframework.aop.framework.ProxyFactoryBean">
      <!--
    <property name="proxyInterfaces"><value>test.model.Soo</value></property>
        -->
    <property name="singleton"><value>false</value></property>
    <property name="target"><ref local="soo"/></property>
    <property name="proxyTargetClass"><value>true</value></property>
    <property name="frozen"><value>true</value></property>
    <property name="interceptorNames">
        <list>
            <value>fooAdvisor</value>
        </list>
    </property>
  </bean>

</beans>


Test case:

//==============================================================================
// Created on 2005-10-31
// $Id$
//==============================================================================
package test;

import junit.framework.TestCase;

import org.springframework.beans.factory.xml.XmlBeanFactory;
import org.springframework.core.io.ClassPathResource;

import test.model.Foo;
import test.model.Soo;

public class SpringTest extends TestCase {
  private static final long LOOP = 200000;
  private XmlBeanFactory factory = null;
  protected void setUp(); throws Exception {
    super.setUp();;
    ClassPathResource res = new ClassPathResource("/spring_component_config.xml");;
    factory = new XmlBeanFactory(res);;
    assertNotNull(factory);;
    Thread.sleep(100);;
    System.gc();;
    Thread.sleep(100);;
    System.gc();;
    Thread.sleep(100);;
  }
  
  protected void tearDown(); throws Exception {
    super.tearDown();;
  }
  
  public void testBenchCreateComponentInstance(); throws Exception{
    new Benchmark("Spring: Create bean without injection", LOOP);{
      public void run(); throws Exception {
        factory.getBean("bar");;
        //Bar bar = (Bar);container.getComponentInstance(Bar.class);;
      }
    }.start(true);;
    
    Soo soo = (Soo);factory.getBean("soo");;
    assertNotNull(soo.getBar(););;
  }
  
  public void testBenchConstructorInjection(); throws Exception{
    new Benchmark("Spring: Create bean with Constructor Dependency Injection", LOOP);{
      public void run(); throws Exception {
        factory.getBean("foo");;
      }
    }.start(true);;
    Foo foo = (Foo);factory.getBean("foo");;
    assertNotNull(foo.getBar(););;
  }
  
  public void testBenchSetterInjectio(); throws Exception{
    new Benchmark("Spring: Create bean with Setter Dependency Injection", LOOP);{
      public void run(); throws Exception {
        factory.getBean("soo");;
      }
    }.start(true);;
    Soo soo = (Soo);factory.getBean("soo");;
    assertNotNull(soo.getBar(););;
  }
  
  public void testBenchEmptyInterceptor(); throws Exception{
     Benchmark bench = new Benchmark("Spring: Bean method invocation with empty interceptor applied", LOOP * 100);{
      Soo soo = (Soo);factory.getBean("sooProxy");;
      public void run(); throws Exception {
        soo.noop();;
      }
    };
    bench.start(true);;
    //new BenchLauncher();.launch(bench,5,true);;
  }
  
  public void testBenchCreateAsectizedBean(); throws Exception{
    new Benchmark("Spring: Create aspectized bean", LOOP );{
      public void run(); throws Exception {
        factory.getBean("sooProxy");;
        //Soo soo = (Soo);factory.getBean("sooProxy");;
        //assertNotNull(soo.getBar(););;
        //System.err.println(soo.getBar(););;
        //soo.getBar();;
        //soo.noop();;
      }
    }.start(true);;
  }
}
0 请登录后投票
   发表时间:2006-01-06  
测试结果, prototype的bean创建,Nuts比Spring快8-10倍。如果和spring集成会慢些,但是仍然有6-7倍。

singleton也测了。简单的getInstance() vs. getBean()的话,Nuts比spring快70%。如果用了Nuts的适合重复调用的getFactory()的话,就要快10倍左右。


对prototype的情况,Factory的作用不明显,可见更多的时间被花在对象创建的开销之上了。

Nuts没有提供out-of-box的aop,所以对aspectized bean没有直接的对应。利用spring aop的话,效率根spring一样低下。不过好在你可以任意插入自己的aop实现,比如用aspectj,或者jade的aop方案。


这是结果

引用


Spring result:

Benchmark of [Spring: Create bean without injection]
  - Loops: 200,000
  - Elapsed: 4867 ms
  - Average: 0.024335 ms/call
  - Speed: 41,093.076 calls/scond
Benchmark of [Spring: Create bean with Constructor Dependency Injection]
  - Loops: 200,000
  - Elapsed: 18517 ms
  - Average: 0.092585 ms/call
  - Speed: 10,800.886 calls/scond
Benchmark of [Spring: Create bean with Setter Dependency Injection]
  - Loops: 200,000
  - Elapsed: 12058 ms
  - Average: 0.06029 ms/call
  - Speed: 16,586.499 calls/scond
Benchmark of [Spring: Create bean with bytype autowiring and Setter Dependency Injection]
  - Loops: 200,000
  - Elapsed: 16665 ms
  - Average: 0.083325 ms/call
  - Speed: 12,001.2 calls/scond
Benchmark of [Spring: Create singleton bean with Setter Dependency Injection]
  - Loops: 2,000,000
  - Elapsed: 971 ms
  - Average: 4.855E-4 ms/call
  - Speed: 2,059,732.235 calls/scond
Benchmark of [Spring: Bean method invocation with empty interceptor applied]
  - Loops: 20,000,000
  - Elapsed: 6340 ms
  - Average: 3.17E-4 ms/call
  - Speed: 3,154,574.132 calls/scond
Benchmark of [Spring: Create aspectized bean]
  - Loops: 20,000
  - Elapsed: 8663 ms
  - Average: 0.43315 ms/call
  - Speed: 2,308.669 calls/scond





Nuts w/o Spring integration:

Benchmark of [Nuts: Create bean without injection]
  - Loops: 200,000
  - Elapsed: 581 ms
  - Average: 0.002905 ms/call
  - Speed: 344,234.079 calls/scond
Benchmark of [Nuts: Create bean with Constructor Dependency Injection]
  - Loops: 200,000
  - Elapsed: 1292 ms
  - Average: 0.00646 ms/call
  - Speed: 154,798.762 calls/scond
Benchmark of [Nuts: Create bean with Setter Dependency Injection]
  - Loops: 200,000
  - Elapsed: 1352 ms
  - Average: 0.00676 ms/call
  - Speed: 147,928.994 calls/scond
Benchmark of [Nuts: Create bean with bytype autowiring and Setter Dependency Injection]
  - Loops: 200,000
  - Elapsed: 2314 ms
  - Average: 0.01157 ms/call
  - Speed: 86,430.424 calls/scond
Benchmark of [Nuts: Create singleton bean with Setter Dependency Injection]
  - Loops: 2,000,000
  - Elapsed: 581 ms
  - Average: 2.905E-4 ms/call
  - Speed: 3,442,340.792 calls/scond
Benchmark of [Nuts: Singleton Bean with Factory]
  - Loops: 2,000,000
  - Elapsed: 101 ms
  - Average: 5.05E-5 ms/call
  - Speed: 19,801,980.198 calls/scond
Benchmark of [Nuts: Singleton Bean with custom factory]
  - Loops: 2,000,000
  - Elapsed: 180 ms
  - Average: 9.0E-5 ms/call
  - Speed: 11,111,111.111 calls/scond
Benchmark of [Nuts: Constructor Injection with Factory]
  - Loops: 200,000
  - Elapsed: 1102 ms
  - Average: 0.00551 ms/call
  - Speed: 181,488.203 calls/scond
Benchmark of [Nuts: Setter Injection with Factory]
  - Loops: 200,000
  - Elapsed: 1232 ms
  - Average: 0.00616 ms/call
  - Speed: 162,337.662 calls/scond







Nuts with Spring integration:

Benchmark of [Nuts: Create bean without injection]
  - Loops: 200,000
  - Elapsed: 712 ms
  - Average: 0.00356 ms/call
  - Speed: 280,898.876 calls/scond
Benchmark of [Nuts: Create bean with Constructor Dependency Injection]
  - Loops: 200,000
  - Elapsed: 1522 ms
  - Average: 0.00761 ms/call
  - Speed: 131,406.045 calls/scond
Benchmark of [Nuts: Create bean with Setter Dependency Injection]
  - Loops: 200,000
  - Elapsed: 1793 ms
  - Average: 0.008965 ms/call
  - Speed: 111,544.897 calls/scond
Benchmark of [Nuts: Create bean with bytype autowiring and Setter Dependency Injection]
  - Loops: 200,000
  - Elapsed: 2875 ms
  - Average: 0.014375 ms/call
  - Speed: 69,565.217 calls/scond
Benchmark of [Nuts: Create singleton bean with Setter Dependency Injection]
  - Loops: 2,000,000
  - Elapsed: 611 ms
  - Average: 3.055E-4 ms/call
  - Speed: 3,273,322.422 calls/scond
Benchmark of [Nuts: Singleton Bean with Factory]
  - Loops: 2,000,000
  - Elapsed: 100 ms
  - Average: 5.0E-5 ms/call
  - Speed: 20,000,000 calls/scond
Benchmark of [Nuts: Singleton Bean with custom factory]
  - Loops: 2,000,000
  - Elapsed: 180 ms
  - Average: 9.0E-5 ms/call
  - Speed: 11,111,111.111 calls/scond
Benchmark of [Nuts: Constructor Injection with Factory]
  - Loops: 200,000
  - Elapsed: 1492 ms
  - Average: 0.00746 ms/call
  - Speed: 134,048.257 calls/scond
Benchmark of [Nuts: Setter Injection with Factory]
  - Loops: 200,000
  - Elapsed: 1633 ms
  - Average: 0.008165 ms/call
  - Speed: 122,473.974 calls/scond
Benchmark of [Nuts: Bean method invocation with empty interceptor applied]
  - Loops: 20,000,000
  - Elapsed: 6320 ms
  - Average: 3.16E-4 ms/call
  - Speed: 3,164,556.962 calls/scond
Benchmark of [Nuts: Create aspectized bean]
  - Loops: 20,000
  - Elapsed: 8783 ms
  - Average: 0.43915 ms/call
  - Speed: 2,277.126 calls/scond

0 请登录后投票
   发表时间:2006-01-07  
引用
不过我的意见,入侵性的大小并非是判断容器好坏的标准,实用才是最重要的. 而且不同的应用场合,对容器要求还不一样. Spring对singleton的bean instantiating(性能)很出色,可是singleton=false,就完蛋了. 所以Spring不适合我自己碰到的一些应用场合. 所以自己造轮子咯. 在我的应用场合中,用annontation这种方法最好,半入侵. 更甚者, 在有些时侯convention 就该over configuration.


这就见仁见智了。确实实用很重要。但是入侵性一样重要。好的框架应该两者都重视。

象convention应该over configuration,没错。但是如果只能convention而不能configuration就不好了。不能为了照顾90%就忽略那10%。

你那个用apache annoation的方法不错。但是如果只有这一种方式就不够灵活。Nuts的宗旨是允许你任意插入,比如你的apache annotation,Nuts没有在核心支持它,但是大可以做个插件插入Nuts里。我对java 5的annotation的支持就是一个插件。

对了,测试了一下spring的singleton,还是比Nuts慢了不少。naive使用nuts的话,spring慢70%,如果用Nuts的"getFactory()"的话,spring要慢10倍。
0 请登录后投票
论坛首页 Java企业应用版

跳转论坛:
Global site tag (gtag.js) - Google Analytics