`
Tin
  • 浏览: 138601 次
  • 性别: Icon_minigender_1
  • 来自: 北京
社区版块
存档分类
最新评论

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

阅读更多

本文在060216进行了修改,因为发现了测试中的错误!注意5.5和7的内容。

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倍,十分可观。

5.5 巨大的反差,原来是我搞错了配置,发现了幕后黑手:
第二天,我又重新运行了5里面的测试。但是结果令人吃惊,运行了十多次,结果于昨天反差巨大,prototype方式获得的bean反而性能最快!
摘要两次测量结果
**************************Autowire Used time:-17578
**************************Prototype Used time:-7609
**************************Proxy Used time:-13063
-----------------------------------------------
**************************Autowire Used time:-17047
**************************Prototype Used time:-7609
**************************Proxy Used time:-12797
这是为什么呢?我百思不得其解,问题出在哪里呢?后来经过跟踪svn里面的提交纪录。我发现,我在昨天测试以后,把spring配置文件中的<beans default-autowire="autodetect">变成了<beans>。也就是没有打开自动检测的autowire!
而后就真相大白了。我有配置上default-autowire="autodetect"进行测试,结果:
**************************Autowire Used time:-16937
**************************Prototype Used time:-79750
**************************Proxy Used time:-12578
这和昨天的测试结果完全相同。也就是说我昨天写的4.77x的结果其实没有实际意义。倒是说明了Spring和Webwork集成的文章上面说的default-autowire="autodetect"是很坏的实践,即失去了name的灵活性也带来了巨大的性能损失。
而如果使用默认的Spring autowire配置下,prototype的性能已经很好了,实际上它工作起来应该是最快的。

6、在实际的Web项目中的性能对比:
我使用了我的一个小项目,就是反复调用一个action获取一个页面,其中有一个DAO注入。使用了JMeter进行了一个测试:2个线程,间隔0.5秒,循环50次,对比“据和报告中的”Throughput,单位/sec。
使用autowire方式:Avg. 148.34(吞吐量越高越好)
使用prototype方式:Avg. 138.5
也就是说在实际应用中两者也是有性能差距的,后者大约是前者性能的93%。
具体代码我不放出了,因为意义不大,大家也可以自己动手试验一下。
补充说明:
首先注意这个测试是在default-autowire="autodetect"下进行的。
测试的这个Action其实是一个空Action,它没有调用service和DAO,只是直接return SUCCESS,然后dispatcher到一个静态内容的jsp页面。我的本意是为了能够在获取Action占据的时间比例比较高的情况下分析性能区别。但是实际上却间接的夸大了在真正的实际应用中的性能差距。实际应用中如果加上service、DAO等逻辑的执行时间、模板View的渲染时间还有广域网上的网络传输时间,那么获取Action实例的时间差距可能就微乎其微了。

7、后续:
经过今天的思考,可以说完全改变了想法,重新汇总一下:
a、在不使用default-autowire="autodetect"时,Webwork 2.2的xwork中的action class使用spring的bean id配置的理论性能最好。而且,我认为如果不是为了追求配置上的简单,严重推荐关闭spring的default-autowire。
b、在使用default-autowire="autodetect、name、class"时,需要考虑你的需求。如果不使用Spring AOP提供的功能则在Webwork 2.2的xwork中的action class使用class全名比较好。如果使用Spring AOP的功能,则还是使用bean id。
c、在Spring中是否使用default-autowire是个需要慎重考虑的问题。autowire如果打开,命名会受到限制(class则更不推荐,受限更大,参考相关文档),它所带来的配置简化我认为只算是小小的语法糖果,背后却是吃掉它所埋下的隐患。
d、6中的测试还是有些说明意义的。7%的性能差距是在使用了default-autowire的方式下得出的,其中测试的那个action其实没有执行什么逻辑,而是一个直接dispatcher到success view的action,如果有商业逻辑包装,则性能差据估计会更小。因为实际上Action的执行过程、service、DAO等逻辑的执行过程和模板View的渲染过程(网络延迟)才是耗时大户。所以,关于性能应该下的结论是,prototype与否,在实际应用中性能差距是很小的,基本可以忽略不计。我们讨论的更多是编码的更好的实践。
e、autowire不使用Spring AOP相对还是trade off,因为虽然配置简单一点,但是对于使用Spring的声明性事务等内容会带来麻烦。虽然XML不那么好,但是显示配置带来的好处还是很多的。
f、谢谢robbin的提示。关于事务我也是无奈,放弃Action事务后难道给DAO多封装一层事务?如何没有事务依然使用HibernateDAOSurpport?Acegi的确不适合Web,使用WW的Inteceptor可以实现更舒适的解决方案。
g、SpringProxyableObjectFactory的问题……使用上难道只能改代码?找了半天没有这个东西的介绍。看来还是需要看看代码。不过发现现在Webwork和Xwork的代码又变动了很多……
h、我的测试是在Webwork2.2+Spring 1.2.6环境下测试的

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

分享到:
评论

相关推荐

    webWork2.2+spring +SpringMVC组合 例子

    【标题】:“webWork2.2+spring+SpringMVC组合例子”是一个示例项目,展示了如何将三个经典的Java Web框架——WebWork2.2、Spring以及Spring MVC整合在一起,以构建一个完整的Web应用程序。这样的组合可以充分利用各...

    WebWork 2.2新特性的PPT.rar

    在"WebWork22new.doc"和"WebWork2_2_new.ppt"这两个文件中,读者可以深入了解到WebWork 2.2的新特性、使用方法以及实际应用案例。通过详细阅读和实践,开发者可以充分利用这些新特性来提高开发效率,构建出更加健壮...

    webwork2.2例子带有lib包

    2. **配置文件**:WebWork使用XML配置文件(如struts-config.xml或webwork.xml)来定义Action的映射、拦截器链和其他设置。这些配置文件告诉WebWork如何处理HTTP请求以及如何跳转到不同的视图。 3. **lib库**:lib...

    WebWork2.2入门

    WebWork2.2是其一个较早但仍然广泛使用的版本,它引入了许多创新特性,如动作映射、拦截器、类型转换等,以提升开发效率和代码质量。 ### MVC架构 在WebWork2.2中,MVC模式是核心设计思想。模型(Model)负责业务...

    webwork2.2

    webwork2.2.jar 类包 web work2

    webwork+spring整合例子 内带使用说明 以及webwork文档(中文)

    2. 在WebWork的配置文件中,配置Spring的ActionServlet,使WebWork能够通过Spring获取Action实例。 3. 创建WebWork动作类,并使用Spring的@Autowired注解来注入所需的依赖。 4. 设置必要的拦截器,以确保Spring的...

    webwork与spring集成

    ### WebWork与Spring集成:深度解析与实践指南 在企业级应用开发中,框架的集成是提高代码可维护性、扩展性和复用性的关键。WebWork框架与Spring框架的集成便是一个典型示例,它结合了WebWork在MVC架构方面的优势与...

    spring与webwork的集成

    这样,WebWork 就可以直接从 Spring 容器中获取 Action 实例。例如,定义一个名为 "some-action" 的 Bean,它对应于 `com.example.actions.SomeAction` 类。配置完成后,WebWork 在处理请求时会自动从 Spring 容器中...

    webwork2.1 spring

    WebWork2.1与Spring的整合是Java Web开发中的...不过,要注意的是,WebWork2.1已经是较旧的版本,现在更推荐使用Struts2(WebWork的后续发展项目)或者Spring MVC作为MVC框架,因为它们有更多的社区支持和更新的特性。

    webwork-register.rar_webwork_webwork 验证_webwork spring

    WebWork和Spring是两个在Java Web开发中广泛使用的框架,它们各自有其独特的优势,并且可以结合使用以增强应用的功能和可维护性。本项目"webwork-register.rar"显然是一个基于WebWork和Spring构建的注册管理系统,让...

    spring与webwork框架集成

    WebWork2.1 与 Spring 框架的集成是一个常见的技术实践,目的是利用 Spring 提供的依赖注入(DI)和面向切面编程(AOP)能力,以及 WebWork 的优秀动作层管理,来构建更加灵活和解耦的Java Web应用。在集成过程中,...

    webwork-2.2.2

    webwork的包。webwork开发者不可缺少的

    spring和webwork包

    标题中的“spring和webwork包”指的两个著名的Java Web框架——Spring框架和WebWork框架。Spring是一个全方位的开源框架,主要用于简化企业级Java应用的开发,它强调了依赖注入(Dependency Injection,DI)和面向切...

    webwork+spring+hibernate 开发资料

    Spring可以通过其Action代理来管理和控制WebWork的动作,同时Spring的AOP特性可以用于处理如日志记录、事务管理等跨切面关注点。 Spring与Hibernate的整合则主要体现在数据访问层。Spring提供了HibernateTemplate或...

    spring+hibernate+webwork相关配置

    5. **整合工作**:将Spring的ApplicationContext加载到WebWork中,这样WebWork的Action可以通过Spring获取依赖的对象。同时,Spring的事务管理器可以控制整个请求范围内的事务,包括Hibernate的操作。 这个配置过程...

    Webwork+spring+hibernate集成实例

    Webwork、Spring和Hibernate是Java开发中的三大框架,它们各自在不同的层面上为应用程序提供服务。Webwork负责处理用户交互,Spring提供依赖注入和管理事务,而Hibernate则专注于对象关系映射(ORM),使得数据库...

    搭建WEBWORK+SPRING+HIBERNATE框架

    【搭建WEBWORK+SPRING+HIBERNATE框架】是一个集成三大流行开源框架的过程,用于构建高效、可扩展的企业级Web应用。以下是详细的步骤和知识点: 1. **开发环境配置**: - 使用MyEclipse 5.5.1 GA作为开发工具,它...

    webwork in action

    根据提供的文件信息,本书《WebWork in Action》主要聚焦于Java WebWork框架的应用与实践,是一本详尽介绍WebWork框架各个方面的书籍。下面将基于标题、描述、标签及部分内容来提取并归纳出相关的IT知识点。 ### ...

Global site tag (gtag.js) - Google Analytics