本文在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(); [...]