Tin's Blog

          You are coming a long way, baby~Thinking, feeling, memory...

            BlogJava :: 首頁(yè) :: 新隨筆 :: 聯(lián)系 :: 聚合  :: 管理 ::
            128 隨筆 :: 0 文章 :: 221 評(píng)論 :: 0 Trackbacks

          本文在060216進(jìn)行了修改,因?yàn)榘l(fā)現(xiàn)了測(cè)試中的錯(cuò)誤!注意5.5和7的內(nèi)容。

          1、引子:
          其實(shí)是ajoo的這篇“Nuts和Spring 1.2.6 效率對(duì)比”和“IoC容器的prototype性能測(cè)試 ”,他們?cè)贘avaeye上詳細(xì)討論了Spring的prototype的缺陷。
          Spring的prototype指的就是singleton="false"的bean,具體可以看Spring參考手冊(cè)“3.2.5. To singleton or not to singleton”介紹。

          2、Webwork 2.2的Spring結(jié)合問(wèn)題:
          Webwork 2.2已經(jīng)拋棄自己的IoC,默認(rèn)使用Spring的IoC。
          上在OpenSymphony的官方Wiki,和jscud后來(lái)的幾篇文章中沒(méi)有特別提出prototype的問(wèn)題。但是托他們的福,我們已經(jīng)順利的使Spring和Webwork良好的協(xié)同工作起來(lái)了。
          可是而后的一些問(wèn)題卻把prototype的問(wèn)題搞得神秘起來(lái)……
          ajoo的測(cè)試中指出Spring的prototype性能很差,參見(jiàn)后面參考中的一篇文章和Javaeye的討論。
          而后又發(fā)現(xiàn)robbin在Javaeye的Wiki上面的“集成webwork和spring”中的最后注到:
          “注意:目前并不推薦使用Spring來(lái)管理Webwork Action,因?yàn)閷?duì)于prototype類(lèi)型的bean來(lái)說(shuō),Spring創(chuàng)建bean和調(diào)用bean的效率是很低的!更進(jìn)一步信息請(qǐng)看IoC容器的prototype性能測(cè)試”
          這就使我們常用的Spring+Webwork2.2的連接中使用的prototype的問(wèn)題被擺出來(lái)了。
          我現(xiàn)在的項(xiàng)目中使用了prototype的方式將Webwork Action使用Spring進(jìn)行顯示的裝配,我擔(dān)心這個(gè)性能的問(wèn)題會(huì)很?chē)?yán)重,所以今天花了半天時(shí)間具體測(cè)試了一下。

          3、Prototype VS autowire的解釋?zhuān)?BR>我不知道怎么命名兩種方式好,所以這里先做個(gè)解釋?zhuān)?BR>spring的配置中Action會(huì)有個(gè)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">

          看起來(lái)相同,但其實(shí)不同(我以前發(fā)過(guò)帖子,其中說(shuō)這幾種方法都可,但是其實(shí)它們的機(jī)制是不同的。

          4、Portotye和autowire在XWork的SpringObjectFactory中是如何運(yùn)作的:
          我們先看一下代碼,就能明白兩者的區(qū)別了:

          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配置會(huì)使用第二個(gè)buildBean方法,而prototype會(huì)使用第一個(gè)buildBean方法。

          5、我的測(cè)試,首先測(cè)試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));
              }

          }

           

          重要的是測(cè)試結(jié)果:
          **************************Used time:-16875
          **************************Used time:-80500
          **************************Used time:-12703(使用SpringProxyableObjectFactory()這個(gè)實(shí)現(xiàn))

          prototype是autowire運(yùn)行時(shí)間的4.77X倍,十分可觀。

          5.5 巨大的反差,原來(lái)是我搞錯(cuò)了配置,發(fā)現(xiàn)了幕后黑手:
          第二天,我又重新運(yùn)行了5里面的測(cè)試。但是結(jié)果令人吃驚,運(yùn)行了十多次,結(jié)果于昨天反差巨大,prototype方式獲得的bean反而性能最快!
          摘要兩次測(cè)量結(jié)果
          **************************Autowire Used time:-17578
          **************************Prototype Used time:-7609
          **************************Proxy Used time:-13063
          -----------------------------------------------
          **************************Autowire Used time:-17047
          **************************Prototype Used time:-7609
          **************************Proxy Used time:-12797

          這是為什么呢?我百思不得其解,問(wèn)題出在哪里呢?后來(lái)經(jīng)過(guò)跟蹤svn里面的提交紀(jì)錄。我發(fā)現(xiàn),我在昨天測(cè)試以后,把spring配置文件中的<beans default-autowire="autodetect">變成了<beans>。也就是沒(méi)有打開(kāi)自動(dòng)檢測(cè)的autowire!
          而后就真相大白了。我有配置上default-autowire="autodetect"進(jìn)行測(cè)試,結(jié)果:
          **************************Autowire Used time:-16937
          **************************Prototype Used time:-79750
          **************************Proxy Used time:-12578

          這和昨天的測(cè)試結(jié)果完全相同。也就是說(shuō)我昨天寫(xiě)的4.77x的結(jié)果其實(shí)沒(méi)有實(shí)際意義。倒是說(shuō)明了Spring和Webwork集成的文章上面說(shuō)的default-autowire="autodetect"是很壞的實(shí)踐,即失去了name的靈活性也帶來(lái)了巨大的性能損失。
          而如果使用默認(rèn)的Spring autowire配置下,prototype的性能已經(jīng)很好了,實(shí)際上它工作起來(lái)應(yīng)該是最快的。

          6、在實(shí)際的Web項(xiàng)目中的性能對(duì)比:
          我使用了我的一個(gè)小項(xiàng)目,就是反復(fù)調(diào)用一個(gè)action獲取一個(gè)頁(yè)面,其中有一個(gè)DAO注入。使用了JMeter進(jìn)行了一個(gè)測(cè)試:2個(gè)線程,間隔0.5秒,循環(huán)50次,對(duì)比“據(jù)和報(bào)告中的”Throughput,單位/sec。
          使用autowire方式:Avg. 148.34(吞吐量越高越好)
          使用prototype方式:Avg. 138.5

          也就是說(shuō)在實(shí)際應(yīng)用中兩者也是有性能差距的,后者大約是前者性能的93%。
          具體代碼我不放出了,因?yàn)橐饬x不大,大家也可以自己動(dòng)手試驗(yàn)一下。
          補(bǔ)充說(shuō)明:
          首先注意這個(gè)測(cè)試是在default-autowire="autodetect"下進(jìn)行的。
          測(cè)試的這個(gè)Action其實(shí)是一個(gè)空Action,它沒(méi)有調(diào)用service和DAO,只是直接return SUCCESS,然后dispatcher到一個(gè)靜態(tài)內(nèi)容的jsp頁(yè)面。我的本意是為了能夠在獲取Action占據(jù)的時(shí)間比例比較高的情況下分析性能區(qū)別。但是實(shí)際上卻間接的夸大了在真正的實(shí)際應(yīng)用中的性能差距。實(shí)際應(yīng)用中如果加上service、DAO等邏輯的執(zhí)行時(shí)間、模板View的渲染時(shí)間還有廣域網(wǎng)上的網(wǎng)絡(luò)傳輸時(shí)間,那么獲取Action實(shí)例的時(shí)間差距可能就微乎其微了。

          7、后續(xù):
          經(jīng)過(guò)今天的思考,可以說(shuō)完全改變了想法,重新匯總一下:
          a、在不使用default-autowire="autodetect"時(shí),Webwork 2.2的xwork中的action class使用spring的bean id配置的理論性能最好。而且,我認(rèn)為如果不是為了追求配置上的簡(jiǎn)單,嚴(yán)重推薦關(guān)閉spring的default-autowire。
          b、在使用default-autowire="autodetect、name、class"時(shí),需要考慮你的需求。如果不使用Spring AOP提供的功能則在Webwork 2.2的xwork中的action class使用class全名比較好。如果使用Spring AOP的功能,則還是使用bean id。
          c、在Spring中是否使用default-autowire是個(gè)需要慎重考慮的問(wèn)題。autowire如果打開(kāi),命名會(huì)受到限制(class則更不推薦,受限更大,參考相關(guān)文檔),它所帶來(lái)的配置簡(jiǎn)化我認(rèn)為只算是小小的語(yǔ)法糖果,背后卻是吃掉它所埋下的隱患。
          d、6中的測(cè)試還是有些說(shuō)明意義的。7%的性能差距是在使用了default-autowire的方式下得出的,其中測(cè)試的那個(gè)action其實(shí)沒(méi)有執(zhí)行什么邏輯,而是一個(gè)直接dispatcher到success view的action,如果有商業(yè)邏輯包裝,則性能差據(jù)估計(jì)會(huì)更小。因?yàn)閷?shí)際上Action的執(zhí)行過(guò)程、service、DAO等邏輯的執(zhí)行過(guò)程和模板View的渲染過(guò)程(網(wǎng)絡(luò)延遲)才是耗時(shí)大戶。所以,關(guān)于性能應(yīng)該下的結(jié)論是,prototype與否,在實(shí)際應(yīng)用中性能差距是很小的,基本可以忽略不計(jì)。我們討論的更多是編碼的更好的實(shí)踐。
          e、autowire不使用Spring AOP相對(duì)還是trade off,因?yàn)殡m然配置簡(jiǎn)單一點(diǎn),但是對(duì)于使用Spring的聲明性事務(wù)等內(nèi)容會(huì)帶來(lái)麻煩。雖然XML不那么好,但是顯示配置帶來(lái)的好處還是很多的。
          f、謝謝robbin的提示。關(guān)于事務(wù)我也是無(wú)奈,放棄Action事務(wù)后難道給DAO多封裝一層事務(wù)?如何沒(méi)有事務(wù)依然使用HibernateDAOSurpport?Acegi的確不適合Web,使用WW的Inteceptor可以實(shí)現(xiàn)更舒適的解決方案。
          g、SpringProxyableObjectFactory的問(wèn)題……使用上難道只能改代碼?找了半天沒(méi)有這個(gè)東西的介紹。看來(lái)還是需要看看代碼。不過(guò)發(fā)現(xiàn)現(xiàn)在Webwork和Xwork的代碼又變動(dòng)了很多……
          h、我的測(cè)試是在Webwork2.2+Spring 1.2.6環(huán)境下測(cè)試的


          8、參考資源:
          Nuts和Spring 1.2.6 效率對(duì)比
          http://www.javaeye.com/pages/viewpage.action?pageId=786
          IoC容器的prototype性能測(cè)試
          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 結(jié)合的幾種方法的小結(jié)
          http://www.aygfsteel.com/scud/archive/2005/09/21/13667.html
          我為什么不推薦對(duì)Action進(jìn)行事務(wù)控制
          http://www.javaeye.com/pages/viewpage.action?pageId=1205
          我為什么不推薦使用Acegi
          http://www.javaeye.com/pages/viewpage.action?pageId=1199

          posted on 2006-02-14 21:48 Tin 閱讀(2393) 評(píng)論(0)  編輯  收藏 所屬分類(lèi): Webwork相關(guān)Spring相關(guān)
          主站蜘蛛池模板: 措勤县| 五寨县| 泰兴市| 兴城市| 云霄县| 开封县| 界首市| 石门县| 南漳县| 诸城市| 繁昌县| 乃东县| 商洛市| 周至县| 丰都县| 吉水县| 平阳县| 涞水县| 甘泉县| 敦化市| 报价| 定日县| 平阳县| 四川省| 林芝县| 时尚| 电白县| 陇川县| 平乡县| 安图县| 鄄城县| 浦北县| 贵州省| 邮箱| 同仁县| 古浪县| 紫云| 札达县| 道孚县| 博爱县| 南康市|