夢(mèng)想飛翔

          自強(qiáng)不息
          posts - 111, comments - 30, trackbacks - 0, articles - 0
            BlogJava :: 首頁(yè) :: 新隨筆 :: 聯(lián)系 :: 聚合  :: 管理
           多數(shù)it 組織都必須解決三個(gè)主要問(wèn)題:1.幫助組織減少成本 2.增加并且保持客戶 3.加快業(yè)務(wù)效率。完成這些問(wèn)題一般都需要實(shí)現(xiàn)對(duì)多個(gè)業(yè)務(wù)系統(tǒng)的數(shù)據(jù)和業(yè)務(wù)邏輯的無(wú)縫訪問(wèn),也就是說(shuō),要實(shí)施系統(tǒng)集成工程,以便聯(lián)結(jié)業(yè)務(wù)流程、實(shí)現(xiàn)數(shù)據(jù)的訪問(wèn)與共享。

            jpetstore 4.0是ibatis的最新示例程序,基于struts mvc框架(注:非傳統(tǒng)struts開(kāi)發(fā)模式),以ibatis作為持久化層。該示例程序設(shè)計(jì)優(yōu)雅,層次清晰,可以學(xué)習(xí)以及作為一個(gè)高效率的編程模型參考。本文是在其基礎(chǔ)上,采用spring對(duì)其中間層(業(yè)務(wù)層)進(jìn)行改造。使開(kāi)發(fā)量進(jìn)一步減少,同時(shí)又擁有了spring的一些好處…

            1. 前言

            jpetstore 4.0是ibatis的最新示例程序。ibatis是開(kāi)源的持久層產(chǎn)品,包含sql maps 2.0 和 data access objects 2.0 框架。jpetstore示例程序很好的展示了如何利用ibatis來(lái)開(kāi)發(fā)一個(gè)典型的j2ee web應(yīng)用程序。jpetstore有如下特點(diǎn):

          • ibatis數(shù)據(jù)層
          • pojo業(yè)務(wù)層
          • pojo領(lǐng)域類
          • struts mvc
          • jsp 表示層

            以下是本文用到的關(guān)鍵技術(shù)介紹,本文假設(shè)您已經(jīng)對(duì)struts,springframewok,ibatis有一定的了解。

          • struts 是目前java web mvc框架中不爭(zhēng)的王者。經(jīng)過(guò)長(zhǎng)達(dá)五年的發(fā)展,struts已經(jīng)逐漸成長(zhǎng)為一個(gè)穩(wěn)定、成熟的框架,并且占有了mvc框架中最大的市場(chǎng)份額。但是struts某些技術(shù)特性上已經(jīng)落后于新興的mvc框架。面對(duì)spring mvc、webwork2 這些設(shè)計(jì)更精密,擴(kuò)展性更強(qiáng)的框架,struts受到了前所未有的挑戰(zhàn)。但站在產(chǎn)品開(kāi)發(fā)的角度而言,struts仍然是最穩(wěn)妥的選擇。本文的原型例子jpetstore 4.0就是基于struts開(kāi)發(fā)的,但是不拘泥于struts的傳統(tǒng)固定用法,例如只用了一個(gè)自定義action類,并且在form bean類的定義上也是開(kāi)創(chuàng)性的,令人耳目一新,稍后將具體剖析一下。
          • spring framework 實(shí)際上是expert one-on-one j2ee design and development 一書(shū)中所闡述的設(shè)計(jì)思想的具體實(shí)現(xiàn)。spring framework的功能非常多。包含aop、orm、dao、context、web、mvc等幾個(gè)部分組成。web、mvc暫不用考慮,jpetstore 4.0用的是更成熟的struts和jsp;dao由于目前hibernate、jdo、ibatis的流行,也不考慮,jpetstore 4.0用的就是ibatis。因此最需要用的是aop、orm、context。context中,最重要的是beanfactory,它能將接口與實(shí)現(xiàn)分開(kāi),非常強(qiáng)大。目前aop應(yīng)用最成熟的還是在事務(wù)管理上。
          • ibatis 是一個(gè)功能強(qiáng)大實(shí)用的sql map工具,不同于其他orm工具(如hibernate),它是將sql語(yǔ)句映射成java對(duì)象,而對(duì)于orm工具,它的sql語(yǔ)句是根據(jù)映射定義生成的。ibatis 以sql開(kāi)發(fā)的工作量和數(shù)據(jù)庫(kù)移植性上的讓步,為系統(tǒng)設(shè)計(jì)提供了更大的自由空間。有ibatis代碼生成的工具,可以根據(jù)ddl自動(dòng)生成ibatis代碼,能減少很多工作量。

            2. jpetstore簡(jiǎn)述

            2.1. 背景

            最初是sun公司的j2ee petstore,其最主要目的是用于學(xué)習(xí)j2ee,但是其缺點(diǎn)也很明顯,就是過(guò)度設(shè)計(jì)了。接著oracle用j2ee petstore來(lái)比較各應(yīng)用服務(wù)器的性能。微軟推出了基于。net平臺(tái)的 pet shop,用于競(jìng)爭(zhēng)j2ee petstore.而jpetstore則是經(jīng)過(guò)改良的基于struts的輕便框架j2ee web應(yīng)用程序,相比來(lái)說(shuō),jpetstore設(shè)計(jì)和架構(gòu)更優(yōu)良,各層定義清晰,使用了很多最佳實(shí)踐和模式,避免了很多"反模式",如使用存儲(chǔ)過(guò)程,在java代碼中嵌入sql語(yǔ)句,把html存儲(chǔ)在數(shù)據(jù)庫(kù)中等等。最新版本是jpetstore 4.0.

            2.2. jpetstore開(kāi)發(fā)運(yùn)行環(huán)境的建立

            1、開(kāi)發(fā)環(huán)境

          • java sdk 1.4.2
          • apache tomcat 4.1.31
          • eclipse-sdk-3.0.1-win32
          • hsqldb 1.7.2

            2、eclipse插件

          • emf sdk 2.0.1:eclipse建模框架,lomboz插件需要,可以使用runtime版本。
          • lomboz 3.0:j2ee插件,用來(lái)在eclipse中開(kāi)發(fā)j2ee應(yīng)用程序
          • spring ide 1.0.3:spring bean配置管理插件
          • xmlbuddy_2.0.10:編輯xml,用免費(fèi)版功能即可
          • tomcatpluginv3:tomcat管理插件
          • properties editor:編輯java的屬性文件,并可以預(yù)覽以及自動(dòng)存盤(pán)為unicode格式。免去了手工或者ant調(diào)用native2ascii的麻煩。
            3.4. 持久層

              在討論業(yè)務(wù)層之前,我們先看一下持久層,如下圖所示:


             

             

              在上文中,我們把iface包下的dao接口歸為業(yè)務(wù)層,在這里不需要做修改。ibatis的sql配置文件也不需要改。要改的是dao實(shí)現(xiàn)類,并在spring的配置文件中配置起來(lái)。

              1、修改基類

              所有的dao實(shí)現(xiàn)類都繼承于basesqlmapdao類。修改basesqlmapdao類如下:

            public class basesqlmapdao extends sqlmapclientdaosupport {
              protected static final int page_size = 4;
              protected sqlmapclienttemplate smctemplate = this.getsqlmapclienttemplate();
              public basesqlmapdao() {
             }
            }

              使basesqlmapdao類改為繼承于spring提供的sqlmapclientdaosupport類,并定義了一個(gè)保護(hù)屬性smctemplate,其類型為sqlmapclienttemplate。關(guān)于sqlmapclienttemplate類的詳細(xì)說(shuō)明請(qǐng)參照附錄中的"spring中文參考手冊(cè)"

              2、修改dao實(shí)現(xiàn)類

              所有的dao實(shí)現(xiàn)類還是繼承于basesqlmapdao類,實(shí)現(xiàn)相應(yīng)的dao接口,但其相應(yīng)的dao操作委托sqlmapclienttemplate來(lái)執(zhí)行,以accountsqlmapdao類為例,部分代碼如下:

                public list getusernamelist() {
                return smctemplate.queryforlist("getusernamelist", null);
              }
              public account getaccount(string username, string password) {
                account account = new account();
                account.setusername(username);
                account.setpassword(password);
                return (account) smctemplate.queryforobject("getaccountbyusernameandpassword", account);
              }
              public void insertaccount(account account) {
               smctemplate.update("insertaccount", account);
               smctemplate.update("insertprofile", account);
               smctemplate.update("insertsignon", account);
              }
             

              就這么簡(jiǎn)單,所有函數(shù)的簽名都是一樣的,只需要查找替換就可以了!

              3、除去工廠類以及相應(yīng)的配置文件

              除去daoconfig.java這個(gè)dao工廠類和相應(yīng)的配置文件dao.xml,因?yàn)閐ao的獲取現(xiàn)在要用spring來(lái)管理。

              4、dao在spring中的配置(applicationcontext.xml)

                <bean id="datasource"
                    class="org.springframework.jdbc.datasource.drivermanagerdatasource">
                    <property name="driverclassname">
                        <value>org.hsqldb.jdbcdriver</value>
                    </property>
                    <property name="url">
                        <value>jdbc:hsqldb:hsql://localhost/xdb</value>
                    </property>
                    <property name="username">
                        <value>sa</value>
                    </property>
                    <property name="password">
                        <value></value>
                    </property>
                </bean>   
                <!-- ibatis sqlmapclient config -->
                <bean id="sqlmapclient"
                    class="org.springframework.orm.ibatis.sqlmapclientfactorybean">
                    <property name="configlocation">
                        <value>
                            classpath:comibatisjpetstorepersistencesqlmapdaosqlsql-map-config.xml
                        </value>
                    </property>
                    <property name="datasource">
                        <ref bean="datasource"/>
                    </property>   
                </bean>
                <!-- transactions -->
                <bean id="transactionmanager"
                    class="org.springframework.jdbc.datasource.datasourcetransactionmanager">
                    <property name="datasource">
                        <ref bean="datasource"/>
                    </property>
                </bean>
                <!-- persistence layer -->
                <bean id="accountdao"
                    class="com.ibatis.jpetstore.persistence.sqlmapdao.accountsqlmapdao">
                    <property name="sqlmapclient">
                        <ref local="sqlmapclient"/>
                    </property>
                </bean>

              具體的語(yǔ)法請(qǐng)參照附錄中的"spring中文參考手冊(cè)".在這里只簡(jiǎn)單解釋一下:

              1. 我們首先創(chuàng)建一個(gè)數(shù)據(jù)源datasource,在這里配置的是hsqldb數(shù)據(jù)庫(kù)。如果是oracle數(shù)據(jù)庫(kù),driverclassname的值是"oracle.jdbc.driver.oracledriver",url的值類似于"jdbc:oracle:thin:@wugfmobile:1521:cdcf".數(shù)據(jù)源現(xiàn)在由spring來(lái)管理,那么現(xiàn)在我們就可以去掉properties目錄下database.properties這個(gè)配置文件了;還有不要忘記修改sql-map-config.xml,去掉 對(duì)它的引用。

              2. sqlmapclient節(jié)點(diǎn)。這個(gè)是針對(duì)ibatis sqlmap的sqlmapclientfactorybean配置。實(shí)際上配置了一個(gè)sqlmapclient的創(chuàng)建工廠類。configlocation屬性配置了ibatis映射文件的名稱。datasource屬性指向了使用的數(shù)據(jù)源,這樣所有使用sqlmapclient的dao都默認(rèn)使用了該數(shù)據(jù)源,除非在dao的配置中另外顯式指定。

              3. transactionmanager節(jié)點(diǎn)。定義了事務(wù),使用的是datasourcetransactionmanager.

              4. 下面就可以定義dao節(jié)點(diǎn)了,如accountdao,它的實(shí)現(xiàn)類是com.ibatis.jpetstore.persistence.sqlmapdao.accountsqlmapdao,使用的sql配置從sqlmapclient中讀取,數(shù)據(jù)庫(kù)連接沒(méi)有特別列出,那么就是默認(rèn)使用sqlmapclient配置的數(shù)據(jù)源datasource.

              這樣,我們就把持久層改造完了,其他的dao配置類似于accountdao.怎么樣?簡(jiǎn)單吧。這次有接口了:) accountdao接口->accountsqlmapdao實(shí)現(xiàn)。

              3.5. 業(yè)務(wù)層

              業(yè)務(wù)層的位置以及相關(guān)類,如下圖所示:


             

             

              在這個(gè)例子中只有3個(gè)業(yè)務(wù)類,我們以orderservice類為例來(lái)改造,這個(gè)類是最復(fù)雜的,其中涉及了事務(wù)。

              1、在applicationcontext配置文件中增加bean的配置:

                <bean id="orderservice"
                    class="org.springframework.transaction.interceptor.transactionproxyfactorybean">
                    <property name="transactionmanager">
                        <ref local="transactionmanager"></ref>
                    </property>
                    <property name="target">
                        <bean class="com.ibatis.jpetstore.service.orderservice">
                            <property name="itemdao">
                                <ref bean="itemdao"/>
                            </property>
                            <property name="orderdao">
                                <ref bean="orderdao"/>
                            </property>
                            <property name="sequencedao">
                                <ref bean="sequencedao"/>
                            </property>
                        </bean>
                    </property>
                    <property name="transactionattributes">
                        <props>
                            <prop key="insert*">propagation_required</prop>
                        </props>
                    </property>
                </bean>

             

              定義了一個(gè)orderservice,還是很容易懂的。為了簡(jiǎn)單起見(jiàn),使用了嵌套bean,其實(shí)現(xiàn)類是com.ibatis.jpetstore.service.orderservice,分別引用了itemdao,orderdao,sequencedao。該bean的insert*實(shí)現(xiàn)了事務(wù)管理(aop方式)。transactionproxyfactorybean自動(dòng)創(chuàng)建一個(gè)事務(wù)advisor, 該advisor包括一個(gè)基于事務(wù)屬性的pointcut,因此只有事務(wù)性的方法被攔截。

          3、示例源程序
          • ibatis示例程序jpetstore 4.0 http://www.ibatis.com/jpetstore/jpetstore.html
          • 改造后的源程序(+spring)(源碼鏈接)

            2.3. 架構(gòu)

            圖1 jpetstore架構(gòu)圖

           

            圖1 是jpetstore架構(gòu)圖,更詳細(xì)的內(nèi)容請(qǐng)參見(jiàn)jpetstore的白皮書(shū)。參照這個(gè)架構(gòu)圖,讓我們稍微剖析一下源代碼,得出jpetstore 4.0的具體實(shí)現(xiàn)圖(見(jiàn)圖2),思路一下子就豁然開(kāi)朗了。前言中提到的非傳統(tǒng)的struts開(kāi)發(fā)模式,關(guān)鍵就在struts action類和form bean類上。

            struts action類只有一個(gè):beanaction.沒(méi)錯(cuò),確實(shí)是一個(gè)!與傳統(tǒng)的struts編程方式很不同。再仔細(xì)研究beanaction類,發(fā)現(xiàn)它其實(shí)是一個(gè)通用類,利用反射原理,根據(jù)url來(lái)決定調(diào)用formbean的哪個(gè)方法。beanaction大大簡(jiǎn)化了struts的編程模式,降低了對(duì)struts的依賴(與struts以及web容器有關(guān)的幾個(gè)類都放在com.ibatis.struts包下,其它的類都可以直接復(fù)用)。利用這種模式,我們會(huì)很容易的把它移植到新的框架如jsf,spring.

            這樣重心就轉(zhuǎn)移到form bean上了,它已經(jīng)不是普通意義上的form bean了。查看源代碼,可以看到它不僅僅有數(shù)據(jù)和校驗(yàn)/重置方法,而且已經(jīng)具有了行為,從這個(gè)意義上來(lái)說(shuō),它更像一個(gè)bo(business object)。這就是前文講到的,beanaction類利用反射原理,根據(jù)url來(lái)決定調(diào)用form bean的哪個(gè)方法(行為)。form bean的這些方法的簽名很簡(jiǎn)單,例如:
          public string myactionmethod() {
             //..work
             return "success";
           }

            方法的返回值直接就是字符串,對(duì)應(yīng)的是forward的名稱,而不再是actionforward對(duì)象,創(chuàng)建actionforward對(duì)象的任務(wù)已經(jīng)由beanaction類代勞了。

            另外,程序還提供了actioncontext工具類,該工具類封裝了request 、response、form parameters、request attributes、session attributes和 application attributes中的數(shù)據(jù)存取操作,簡(jiǎn)單而線程安全,form bean類使用該工具類可以進(jìn)一步從表現(xiàn)層框架解耦。[iocblog.net 來(lái)源]

            在這里需要特別指出的是,beanaction類是對(duì)struts擴(kuò)展的一個(gè)有益嘗試,雖然提供了非常好的應(yīng)用開(kāi)發(fā)模式,但是它還非常新,一直在發(fā)展中。

            圖2 jpetstore 4.0具體實(shí)現(xiàn)

           

            2.4. 代碼剖析

            下面就讓我們開(kāi)始進(jìn)一步分析jpetstore4.0的源代碼,為下面的改造鋪路。

          • beanaction.java是唯一一個(gè)struts action類,位于com.ibatis.struts包下。正如上文所言,它是一個(gè)通用的控制類,利用反射機(jī)制,把控制轉(zhuǎn)移到form bean的某個(gè)方法來(lái)處理。詳細(xì)處理過(guò)程參考其源代碼,簡(jiǎn)單明晰。
          • form bean類位于com.ibatis.jpetstore.presentation包下,命名規(guī)則為***bean。form bean類全部繼承于basebean類,而basebean類實(shí)際繼承于actionform,因此,form bean類就是struts的 actionform,form bean類的屬性數(shù)據(jù)就由struts框架自動(dòng)填充。而實(shí)際上,jpetstore4.0擴(kuò)展了struts中actionform的應(yīng)用: form bean類還具有行為,更像一個(gè)bo,其行為(方法)由beanaction根據(jù)配置(struts-config.xml)的url來(lái)調(diào)用。雖然如此,我們還是把form bean類定位于表現(xiàn)層。

              struts-config.xml的配置里有3種映射方式,來(lái)告訴beanaction把控制轉(zhuǎn)到哪個(gè)form bean對(duì)象的哪個(gè)方法來(lái)處理。

              以這個(gè)請(qǐng)求連接為例http://localhost/jpetstore4/shop/vieworder.do

              1. url pattern
                <action path="/shop/vieworder" type="com.ibatis.struts.beanaction"
                name="orderbean" scope="session"
                validate="false">
                <forward name="success" path="/order/vieworder.jsp"/>
              </action>
             

            此種方式表示,控制將被轉(zhuǎn)發(fā)到"orderbean"這個(gè)form bean對(duì)象 的"vieworder"方法(行為)來(lái)處理。方法名取"path"參數(shù)的以"/"分隔的最后一部分。

            2. method parameter

           

              <action path="/shop/vieworder" type="com.ibatis.struts.beanaction"
              name="orderbean" parameter="vieworder" scope="session"
              validate="false">
              <forward name="success" path="/order/vieworder.jsp"/>
            </action>
           

            此種方式表示,控制將被轉(zhuǎn)發(fā)到"orderbean"這個(gè)form bean對(duì)象的"vieworder"方法(行為)來(lái)處理。配置中的"parameter"參數(shù)表示form bean類上的方法。"parameter"參數(shù)優(yōu)先于"path"參數(shù)。

            3. no method call

           

              <action path="/shop/vieworder" type="com.ibatis.struts.beanaction"
              name="orderbean" parameter="*" scope="session"
              validate="false">
              <forward name="success" path="/order/vieworder.jsp"/>
            </action>

            此種方式表示,form bean上沒(méi)有任何方法被調(diào)用。如果存在"name"屬性,則struts把表單參數(shù)等數(shù)據(jù)填充到form bean對(duì)象后,把控制轉(zhuǎn)發(fā)到"success".否則,如果name為空,則直接轉(zhuǎn)發(fā)控制到"success".

            這就相當(dāng)于struts內(nèi)置的org.apache.struts.actions.forwardaction的功能

          <action path="/shop/vieworder" type="org.apache.struts.actions.forwardaction"
              parameter="/order/vieworder.jsp " scope="session" validate="false">
           </action>

          • service類位于com.ibatis.jpetstore.service包下,屬于業(yè)務(wù)層。這些類封裝了業(yè)務(wù)以及相應(yīng)的事務(wù)控制。service類由form bean類來(lái)調(diào)用。
          • com.ibatis.jpetstore.persistence.iface包下的類是dao接口,屬于業(yè)務(wù)層,其屏蔽了底層的數(shù)據(jù)庫(kù)操作,供具體的service類來(lái)調(diào)用。daoconfig類是工具類(dao工廠類),service類通過(guò)daoconfig類來(lái)獲得相應(yīng)的dao接口,而不用關(guān)心底層的具體數(shù)據(jù)庫(kù)操作,實(shí)現(xiàn)了如圖2中{耦合2}的解耦。
          • com.ibatis.jpetstore.persistence.sqlmapdao包下的類是對(duì)應(yīng)dao接口的具體實(shí)現(xiàn),在jpetstore4.0中采用了ibatis來(lái)實(shí)現(xiàn)orm。這些實(shí)現(xiàn)類繼承basesqlmapdao類,而basesqlmapdao類則繼承ibatis dao 框架中的sqlmapdaotemplate類。ibatis的配置文件存放在com.ibatis.jpetstore.persistence.sqlmapdao.sql目錄下。這些類和配置文件位于數(shù)據(jù)層
          • domain類位于com.ibatis.jpetstore.domain包下,是普通的javabean。在這里用作數(shù)據(jù)傳輸對(duì)象(dto),貫穿視圖層、業(yè)務(wù)層和數(shù)據(jù)層,用于在不同層之間傳輸數(shù)據(jù)。

            剩下的部分就比較簡(jiǎn)單了,請(qǐng)看具體的源代碼,非常清晰。

            2.5. 需要改造的地方

            jpetstore4.0的關(guān)鍵就在struts action類和form bean類上,這也是其精華之一(雖然該實(shí)現(xiàn)方式是試驗(yàn)性,待擴(kuò)充和驗(yàn)證),在此次改造中我們要保留下來(lái),即控制層一點(diǎn)不變,表現(xiàn)層獲取相應(yīng)業(yè)務(wù)類的方式變了(要加載spring環(huán)境),其它保持不變。要特別關(guān)注的改動(dòng)是業(yè)務(wù)層和持久層,幸運(yùn)的是jpetstore4.0設(shè)計(jì)非常好,需要改動(dòng)的地方非常少,而且由模式可循,如下:

            1. 業(yè)務(wù)層和數(shù)據(jù)層用spring beanfactory機(jī)制管理。

            2. 業(yè)務(wù)層的事務(wù)由spring 的aop通過(guò)聲明來(lái)完成。

            3. 表現(xiàn)層(form bean)獲取業(yè)務(wù)類的方法改由自定義工廠類來(lái)實(shí)現(xiàn)(加載spring環(huán)境)。

            3. jpetstore的改造

            3.1. 改造后的架構(gòu)

           


           

           

            其中紅色部分是要增加的部分,藍(lán)色部分是要修改的部分。下面就讓我們逐一剖析。

            3.2. spring context的加載

            為了在struts中加載spring context,一般會(huì)在struts-config.xml的最后添加如下部分:

          <plug-in classname="org.springframework.web.struts.contextloaderplugin">
          <set-property property="contextconfiglocation"
          value="/web-inf/applicationcontext.xml" />
          </plug-in>

            spring在設(shè)計(jì)時(shí)就充分考慮到了與struts的協(xié)同工作,通過(guò)內(nèi)置的struts plug-in在兩者之間提供了良好的結(jié)合點(diǎn)。但是,因?yàn)樵谶@里我們一點(diǎn)也不改動(dòng)jpetstore的控制層(這是jpetstore4.0的精華之一),所以本文不準(zhǔn)備采用此方式來(lái)加載applicationcontext.我們利用的是spring framework 的beanfactory機(jī)制,采用自定義的工具類(bean工廠類)來(lái)加載spring的配置文件,從中可以看出spring有多靈活,它提供了各種不同的方式來(lái)使用其不同的部分/層次,您只需要用你想用的,不需要的部分可以不用。

            具體的來(lái)說(shuō),就是在com.ibatis.spring包下創(chuàng)建custombeanfactory類,spring的配置文件applicationcontext.xml也放在這個(gè)目錄下。以下就是該類的全部代碼,很簡(jiǎn)單:

          public final class custombeanfactory {
           static xmlbeanfactory factory = null;
           static {
            resource is = new
          inputstreamresource( custombeanfactory.class.getresourceasstream("applicationcontext.xml"));
            factory = new xmlbeanfactory(is);
           }
           public static object getbean(string beanname){
            return factory.getbean(beanname);
           }
          }

            實(shí)際上就是封裝了spring 的xmlbeanfactory而已,并且spring的配置文件只需要加載一次,以后就可以直接用custombeanfactory.getbean("somebean")來(lái)獲得需要的對(duì)象了(例如somebean),而不需要知道具體的類。custombeanfactory類用于{耦合1}的解耦。

            custombeanfactory類在本文中只用于表現(xiàn)層的form bean對(duì)象獲得service類的對(duì)象,因?yàn)槲覀儧](méi)有把form bean對(duì)象配置在applicationcontext.xml中。但是,為什么不把表現(xiàn)層的form bean類也配置起來(lái)呢,這樣就用不著這custombeanfactory個(gè)類了,spring會(huì)幫助我們創(chuàng)建需要的一切?問(wèn)題的答案就在于form bean類是struts的actionform類!如果大家熟悉struts,就會(huì)知道actionform類是struts自動(dòng)創(chuàng)建的:在一次請(qǐng)求中,struts判斷,如果actionform實(shí)例不存在,就創(chuàng)建一個(gè)actionform對(duì)象,把客戶提交的表單數(shù)據(jù)保存到actionform對(duì)象中。因此formbean類的對(duì)象就不能由spring來(lái)創(chuàng)建,但是service類以及數(shù)據(jù)層的dao類可以,所以只有他們?cè)趕pring中配置。

            所以,很自然的,我們就創(chuàng)建了custombeanfactory類,在表現(xiàn)層來(lái)銜接struts和spring.就這么簡(jiǎn)單,實(shí)現(xiàn)了另一種方式的{耦合一}的解耦。

            3.3. 表現(xiàn)層

            上面分析到,struts和spring是在表現(xiàn)層銜接起來(lái)的,那么表現(xiàn)層就要做稍微的更改,即所需要的service類的對(duì)象創(chuàng)建上。以表現(xiàn)層的accountbean類為例:

            原來(lái)的源代碼如下

              private static final accountservice accountservice = accountservice.getinstance();
            private static final catalogservice catalogservice = catalogservice.getinstance();

            改造后的源代碼如下

          private static final accountservice accountservice = (accountservice)custombeanfactory.getbean("accountservice");
          private static final catalogservice catalogservice = (catalogservice)custombeanfactory.getbean("catalogservice");

            其他的幾個(gè)presentation類以同樣方式改造。這樣,表現(xiàn)層就完成了。關(guān)于表現(xiàn)層的其它部分如jsp等一概不動(dòng)。也許您會(huì)說(shuō),沒(méi)有看出什么特別之處的好處啊?你還是額外實(shí)現(xiàn)了一個(gè)工廠類。別著急,帷幕剛剛開(kāi)啟,spring是在表現(xiàn)層引入,但您發(fā)沒(méi)發(fā)現(xiàn):

          • presentation類僅僅面向service類的接口編程,具體"accountservice"是哪個(gè)實(shí)現(xiàn)類,presentation類不知道,是在spring的配置文件里配置。(本例中,為了最大限度的保持原來(lái)的代碼不作變化,沒(méi)有抽象出接口)。spring鼓勵(lì)面向接口編程,因?yàn)槭侨绱说姆奖愫妥匀唬?dāng)然您也可以不這么做。
          • custombeanfactory這個(gè)工廠類為什么會(huì)如此簡(jiǎn)單,因?yàn)槠渲苯邮褂昧藄pring的beanfactory。spring從其核心而言,是一個(gè)di容器,其設(shè)計(jì)哲學(xué)是提供一種無(wú)侵入式的高擴(kuò)展性的框架。為了實(shí)現(xiàn)這個(gè)目標(biāo),spring 大量引入了java 的reflection機(jī)制,通過(guò)動(dòng)態(tài)調(diào)用的方式避免硬編碼方式的約束,并在此基礎(chǔ)上建立了其核心組件beanfactory,以此作為其依賴注入機(jī)制的實(shí)現(xiàn)基礎(chǔ)。org.springframework.beans包中包括了這些核心組件的實(shí)現(xiàn)類,核心中的核心為beanwrapper和beanfactory類。[iocblog.net 來(lái)源]
             2、業(yè)務(wù)類的修改

              以orderservice為例:
            public class orderservice {

               /* private fields */
              private itemdao itemdao;
              private orderdao orderdao;
              private sequencedao sequencedao;

              /* constructors */

              public orderservice() {
              }

            /**
             * @param itemdao 要設(shè)置的 itemdao。
             */
            public final void setitemdao(itemdao itemdao) {
             this.itemdao = itemdao;
            }
            /**
             * @param orderdao 要設(shè)置的 orderdao。
             */
            public final void setorderdao(orderdao orderdao) {
             this.orderdao = orderdao;
            }
            /**
             * @param sequencedao 要設(shè)置的 sequencedao。
             */
            public final void setsequencedao(sequencedao sequencedao) {
             this.sequencedao = sequencedao;
            }
            //剩下的部分
            …….
            }

              紅色部分為修改部分。spring采用的是type2的設(shè)置依賴注入,所以我們只需要定義屬性和相應(yīng)的設(shè)值函數(shù)就可以了,itemdao,orderdao,sequencedao的值由spring在運(yùn)行期間注入。構(gòu)造函數(shù)就可以為空了,另外也不需要自己編寫(xiě)代碼處理事務(wù)了(事務(wù)在配置中聲明),daomanager.starttransaction();等與事務(wù)相關(guān)的語(yǔ)句也可以去掉了。和原來(lái)的代碼比較一下,是不是處理精簡(jiǎn)了很多!可以更關(guān)注業(yè)務(wù)的實(shí)現(xiàn)。

              4. 結(jié)束語(yǔ)

              ibatis是一個(gè)功能強(qiáng)大實(shí)用的sql map工具,可以直接控制sql,為系統(tǒng)設(shè)計(jì)提供了更大的自由空間。其提供的最新示例程序jpetstore 4.0,設(shè)計(jì)優(yōu)雅,應(yīng)用了迄今為止很多最佳實(shí)踐和設(shè)計(jì)模式,非常適于學(xué)習(xí)以及在此基礎(chǔ)上創(chuàng)建輕量級(jí)的j2ee web應(yīng)用程序。jpetstore 4.0是基于struts的,本文在此基礎(chǔ)上,最大程度保持了原有設(shè)計(jì)的精華以及最小的代碼改動(dòng)量,在業(yè)務(wù)層和持久化層引入了spring。在您閱讀了本文以及改造后的源代碼后,會(huì)深切的感受到spring帶來(lái)的種種好處:自然的面向接口的編程,業(yè)務(wù)對(duì)象的依賴注入,一致的數(shù)據(jù)存取框架和聲明式的事務(wù)處理,統(tǒng)一的配置文件…更重要的是spring既是全面的又是模塊化的,spring有分層的體系結(jié)構(gòu),這意味著您能選擇僅僅使用它任何一個(gè)獨(dú)立的部分,就像本文,而它的架構(gòu)又是內(nèi)部一致。

          主站蜘蛛池模板: 马边| 大名县| 福贡县| 永年县| 华宁县| 桑植县| 安阳县| 聂拉木县| 棋牌| 同江市| 兴安盟| 金湖县| 丽水市| 岳西县| 镇平县| 汕头市| 祁门县| 乌海市| 曲阳县| 灵台县| 天门市| 古田县| 乐平市| 昌吉市| 双柏县| 松溪县| 乌拉特后旗| 清远市| 板桥市| 成都市| 额尔古纳市| 汤原县| 微山县| 托克逊县| 兴山县| 凤翔县| 元朗区| 乾安县| 汶上县| 临颍县| 项城市|