Vincent.Chan‘s Blog

常用链接

统计

积分与排名

网站

最新评论

Webwork 2.2的Action是否使用Spring的prototype­获取的性能对比

1、引子:
其实是ajoo的这篇“Nuts和Spring 1.2.6 效率对比”和“IoC容器的prototype性能测试 ”,他们在Javaeye上详细讨论了Spring的prototype的缺陷。
Spring的prototype指的就是singleton="false"的bean,具体可以看Spring参考手册“3.2.5. To singleton or not to singleton”介绍。

2、Webwork 2.2的Spring结合问题:
Webwork 2.2已经抛弃自己的IoC,默认使用Spring的IoC。
上在OpenSymphony的官方Wiki,和jscud后来的几篇文章中没有特别提出prototype的问题。但是托他们的福,我们已经顺利的使Spring和Webwork良好的协同工作起来了。
可是而后的一些问题却把prototype的问题搞得神秘起来……
ajoo的测试中指出Spring的prototype性能很差,参见后面参考中的一篇文章和Javaeye的讨论。
而后又发现robbin在Javaeye的Wiki上面的“集成webwork和spring”中的最后注到:
“注意:目前并不推荐使用Spring来管理Webwork Action,因为对于prototype类型的bean来说,Spring创建bean和调用bean的效率是很低的!更进一步信息请看IoC容器的prototype性能测试”
这就使我们常用的Spring+Webwork2.2的连接中使用的prototype的问题被摆出来了。
我现在的项目中使用了prototype的方式将Webwork Action使用Spring进行显示的装配,我担心这个性能的问题会很严重,所以今天花了半天时间具体测试了一下。

3、Prototype VS autowire的解释:
我不知道怎么命名两种方式好,所以这里先做个解释:
spring的配置中Action会有个id,如:

<bean id="someAction" class="com.tin.action.SomeAction" parent="basicActionWithAuthtication" singleton="false">
 
<property name="someDAO">
  
<ref bean="someDAO" />
 
</property>
</bean>

我指的prototype方式就是在xwork中这样配置:

<action name="someAction" class="someAction">

而autowire方式就是指在xwork中这样配置:

<action name="someAction" class="com.tin.action.SomeAction">

看起来相同,但其实不同(我以前发过帖子,其中说这几种方法都可,但是其实它们的机制是不同的。

4、Portotye和autowire在XWork的SpringObjectFactory中是如何运作的:
我们先看一下代码,就能明白两者的区别了:

public Object buildBean(String beanName, Map extraContext) throws Exception {
 
try {
            
return appContext.getBean(beanName);
        }
 catch (NoSuchBeanDefinitionException e) {
            Class beanClazz 
= getClassInstance(beanName);
            
return buildBean(beanClazz, extraContext);
        }

    }


    
public Object buildBean(Class clazz, Map extraContext) throws Exception {
        Object bean;

        
try {
            bean 
= autoWiringFactory.autowire(clazz, AutowireCapableBeanFactory.AUTOWIRE_CONSTRUCTOR, false);
        }
 catch (UnsatisfiedDependencyException e) {
            
// Fall back
            bean = super.buildBean(clazz, extraContext);
        }


        bean 
= autoWiringFactory.applyBeanPostProcessorsBeforeInitialization(bean, bean.getClass().getName());
        
// We don't need to call the init-method since one won't be registered.
        bean = autoWiringFactory.applyBeanPostProcessorsAfterInitialization(bean, bean.getClass().getName());

        
return autoWireBean(bean, autoWiringFactory);
    }


    
public Object autoWireBean(Object bean) {
        
return autoWireBean(bean, autoWiringFactory);
    }


如果按照autowire配置会使用第二个buildBean方法,而prototype会使用第一个buildBean方法。

5、我的测试,首先测试SpringObjectFactory的理论效率:

public class testSpringObjectFactory extends TestCase {
    
protected FileSystemXmlApplicationContext appContext;
    
protected SpringObjectFactory sof = null;
    
protected Map map = null;
    
final String[] paths = {
            
"WebRoot/WEB-INF/applicationContext.xml",
            
"WebRoot/WEB-INF/spring-daos.xml",
            
"WebRoot/WEB-INF/spring-actions.xml"
        }
;

    
protected void setUp() throws Exception {
        
super.setUp();
        appContext 
= new FileSystemXmlApplicationContext(paths);

        sof 
= new SpringObjectFactory();
        sof.setApplicationContext(appContext);
        sof.setAutowireStrategy(AutowireCapableBeanFactory.AUTOWIRE_BY_NAME);

        map 
= new HashMap();
    }


    
public void testSpringObjectFacotyWithAutowire() {
        
long begin = System.currentTimeMillis();

        
try {
            
for (int i = 0; i < 100000; i++{
                sof.buildBean(
"com.wqh.action.XinfangNewsAction", map);
            }

        }
 catch (Exception e) {
            e.printStackTrace();
        }


        
long end = System.currentTimeMillis();
        System.out.println(
"**************************Used time:" +
            (begin 
- end));
    }


    
public void testSpringObjectFacotyWithPrototype() {
        
long begin = System.currentTimeMillis();

        
try {
            
for (int i = 0; i < 100000; i++{
                sof.buildBean(
"xinfangNewsAction", map);
            }

        }
 catch (Exception e) {
            e.printStackTrace();
        }


        
long end = System.currentTimeMillis();
        System.out.println(
"**************************Used time:" +
            (begin 
- end));
    }

    
    
public void testSpringObjectFacotyWithSpringProxyableObjectFactory() {
        sof 
= new SpringProxyableObjectFactory();
        sof.setApplicationContext(appContext);
        sof.setAutowireStrategy(AutowireCapableBeanFactory.AUTOWIRE_BY_NAME);

        
long begin = System.currentTimeMillis();

        
try {
            
for (int i = 0; i < 100000; i++{
                sof.buildBean(
"com.wqh.action.XinfangNewsAction", map);
            }

        }
 catch (Exception e) {
            e.printStackTrace();
        }


        
long end = System.currentTimeMillis();
        System.out.println(
"**************************Used time:" +
            (begin 
- end));
    }

}

 

重要的是测试结果:
**************************Used time:-16875
**************************Used time:-80500
**************************Used time:-12703(使用SpringProxyableObjectFactory()这个实现)

prototype是autowire运行时间的4.77X倍,十分可观。

6、在实际的Web项目中的性能对比:
我使用了我的一个小项目,就是反复调用一个action获取一个页面,其中有一个DAO注入。使用了JMeter进行了一个测试:2个线程,间隔0.5秒,循环50次,对比“据和报告中的”Throughput,单位/sec。
使用autowire方式:Avg. 148.34(吞吐量越高越好)
使用prototype方式:Avg. 138.5

也就是说在实际应用中两者也是有性能差距的,后者大约是前者性能的93%。
具体代码我不放出了,因为意义不大,大家也可以自己动手试验一下。

7、后续:
如果理想测试下两者性能差距4.7倍,实际性能差距在7%左右。这基本上让我心里有点底了。
但是使用autowire还是有trade off的。失去了Spring的显示配置,也难使用Spring的AOP支持,这样Spring的声明性事务就不容易使用了,像Acegi这样的安全框架也难以使用。所以这需要自己选择了。
但 是注意5中结果里面的SpringProxyableObjectFactory性能非常好,我看了下代码,它将调用过的bean注册到Spring的 BeanRegistry中,性能还是很不错的,但是为什么快我还没有仔细看,如何配置我也不太清楚,希望明白的朋友跟进讲解。

8、参考资源:
Nuts和Spring 1.2.6 效率对比
http://www.javaeye.com/pages/viewpage.action?pageId=786
IoC容器的prototype性能测试
http://forum.javaeye.com/viewtopic.php?t=17622&postdays=0&postorder=asc&start=0
JavaEye的Wiki:集成webwork和spring
http://www.javaeye.com/pages/viewpage.action?pageId=860
WebWork - Spring官方Wiki
http://www.opensymphony.com/webwork/wikidocs/Spring.html
webwork2 + spring 结合的几种方法的小结
http://forum.javaeye.com/viewtopic.php?t=9990
WebWork2.2中结合Spring:"新的方式"
http://www.blogjava.net/scud/archive/2005/09/21/13667.html

posted on 2006-02-14 23:30 Vincent.Chen 阅读(580) 评论(0)  编辑  收藏 所属分类: WebWork&Struts


只有注册用户登录后才能发表评论。


网站导航: