锁定老帖子 主题:IoC容器的prototype性能测试
该帖已经被评为精华帖
|
|
---|---|
作者 | 正文 |
发表时间:2005-12-17
http://www.iteye.com/pages/viewpage.action?pageId=559 对比spring2.0的侵入性方案(要求依赖容器的annotation),大家觉得哪个好呢? 声明:ITeye文章版权属于作者,受法律保护。没有作者书面许可不得转载。
推荐链接
|
|
返回顶楼 | |
发表时间: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. |
|
返回顶楼 | |
发表时间:2005-12-22
引用 可是singleton=false,就完蛋了
为什么?spring支持prototype的呀。 |
|
返回顶楼 | |
发表时间:2005-12-22
ajoo 写道 引用 可是singleton=false,就完蛋了
为什么?spring支持prototype的呀。 spring instantiating prototype 类型的bean效率很低, 创建prototype的BeanProxy效率更低 |
|
返回顶楼 | |
发表时间:2005-12-24
可是。application context一般不是让你重复地getBean()用的阿。
理想情况应该是你getBean()一次或者几次,获得系统运行的必要的几个对象网,然后就洒有纳拉了。这时候prototype是否效率高很重要么? |
|
返回顶楼 | |
发表时间: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效率难道不重要么? |
|
返回顶楼 | |
发表时间: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都调用容器。效率应该也是一个需要考虑的问题。 |
|
返回顶楼 | |
发表时间: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);; } } |
|
返回顶楼 | |
发表时间: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 |
|
返回顶楼 | |
发表时间: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倍。 |
|
返回顶楼 | |