本文在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组合例子”是一个示例项目,展示了如何将三个经典的Java Web框架——WebWork2.2、Spring以及Spring MVC整合在一起,以构建一个完整的Web应用程序。这样的组合可以充分利用各...
在"WebWork22new.doc"和"WebWork2_2_new.ppt"这两个文件中,读者可以深入了解到WebWork 2.2的新特性、使用方法以及实际应用案例。通过详细阅读和实践,开发者可以充分利用这些新特性来提高开发效率,构建出更加健壮...
2. **配置文件**:WebWork使用XML配置文件(如struts-config.xml或webwork.xml)来定义Action的映射、拦截器链和其他设置。这些配置文件告诉WebWork如何处理HTTP请求以及如何跳转到不同的视图。 3. **lib库**:lib...
WebWork2.2是其一个较早但仍然广泛使用的版本,它引入了许多创新特性,如动作映射、拦截器、类型转换等,以提升开发效率和代码质量。 ### MVC架构 在WebWork2.2中,MVC模式是核心设计思想。模型(Model)负责业务...
webwork2.2.jar 类包 web work2
2. 在WebWork的配置文件中,配置Spring的ActionServlet,使WebWork能够通过Spring获取Action实例。 3. 创建WebWork动作类,并使用Spring的@Autowired注解来注入所需的依赖。 4. 设置必要的拦截器,以确保Spring的...
### WebWork与Spring集成:深度解析与实践指南 在企业级应用开发中,框架的集成是提高代码可维护性、扩展性和复用性的关键。WebWork框架与Spring框架的集成便是一个典型示例,它结合了WebWork在MVC架构方面的优势与...
这样,WebWork 就可以直接从 Spring 容器中获取 Action 实例。例如,定义一个名为 "some-action" 的 Bean,它对应于 `com.example.actions.SomeAction` 类。配置完成后,WebWork 在处理请求时会自动从 Spring 容器中...
WebWork2.1与Spring的整合是Java Web开发中的...不过,要注意的是,WebWork2.1已经是较旧的版本,现在更推荐使用Struts2(WebWork的后续发展项目)或者Spring MVC作为MVC框架,因为它们有更多的社区支持和更新的特性。
WebWork和Spring是两个在Java Web开发中广泛使用的框架,它们各自有其独特的优势,并且可以结合使用以增强应用的功能和可维护性。本项目"webwork-register.rar"显然是一个基于WebWork和Spring构建的注册管理系统,让...
WebWork2.1 与 Spring 框架的集成是一个常见的技术实践,目的是利用 Spring 提供的依赖注入(DI)和面向切面编程(AOP)能力,以及 WebWork 的优秀动作层管理,来构建更加灵活和解耦的Java Web应用。在集成过程中,...
webwork的包。webwork开发者不可缺少的
标题中的“spring和webwork包”指的两个著名的Java Web框架——Spring框架和WebWork框架。Spring是一个全方位的开源框架,主要用于简化企业级Java应用的开发,它强调了依赖注入(Dependency Injection,DI)和面向切...
Spring可以通过其Action代理来管理和控制WebWork的动作,同时Spring的AOP特性可以用于处理如日志记录、事务管理等跨切面关注点。 Spring与Hibernate的整合则主要体现在数据访问层。Spring提供了HibernateTemplate或...
5. **整合工作**:将Spring的ApplicationContext加载到WebWork中,这样WebWork的Action可以通过Spring获取依赖的对象。同时,Spring的事务管理器可以控制整个请求范围内的事务,包括Hibernate的操作。 这个配置过程...
Webwork、Spring和Hibernate是Java开发中的三大框架,它们各自在不同的层面上为应用程序提供服务。Webwork负责处理用户交互,Spring提供依赖注入和管理事务,而Hibernate则专注于对象关系映射(ORM),使得数据库...
【搭建WEBWORK+SPRING+HIBERNATE框架】是一个集成三大流行开源框架的过程,用于构建高效、可扩展的企业级Web应用。以下是详细的步骤和知识点: 1. **开发环境配置**: - 使用MyEclipse 5.5.1 GA作为开发工具,它...
根据提供的文件信息,本书《WebWork in Action》主要聚焦于Java WebWork框架的应用与实践,是一本详尽介绍WebWork框架各个方面的书籍。下面将基于标题、描述、标签及部分内容来提取并归纳出相关的IT知识点。 ### ...