blog.Toby

            BlogJava :: 首頁(yè) :: 新隨筆 :: 聯(lián)系 :: 聚合  :: 管理 ::
            130 隨筆 :: 2 文章 :: 150 評(píng)論 :: 0 Trackbacks
          多數(shù) IT 組織都必須解決三個(gè)主要問(wèn)題: 1 .幫助組織減少成本 2 .增加并且保持客戶(hù) 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)域類(lèi)

          • Struts MVC

          • JSP 表示層

          以下是本文用到的關(guān)鍵技術(shù)介紹,本文假設(shè)您已經(jīng)對(duì) Struts SpringFramewok ibatis 有一定的了解,如果不是,請(qǐng)首先查閱附錄中的參考資料。

          • 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 類(lèi),并且在 form bean 類(lèi)的定義上也是開(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 、示例源程序

          • 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 類(lèi)和 form bean 類(lèi)上。

          struts Action 類(lèi)只有一個(gè): BeanAction 。沒(méi)錯(cuò),確實(shí)是一個(gè)!與傳統(tǒng)的 struts 編程方式很不同。再仔細(xì)研究 BeanAction 類(lèi),發(fā)現(xiàn)它其實(shí)是一個(gè)通用類(lèi),利用反射原理,根據(jù) URL 來(lái)決定調(diào)用 formbean 的哪個(gè)方法。 BeanAction 大大簡(jiǎn)化了 struts 的編程模式,降低了對(duì) struts 的依賴(lài)(與 struts 以及 WEB 容器有關(guān)的幾個(gè)類(lèi)都放在 com.ibatis.struts 包下,其它的類(lèi)都可以直接復(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 類(lèi)利用反射原理,根據(jù) URL 來(lái)決定調(diào)用 form bean 的哪個(gè)方法(行為)。 form bean 的這些方法的簽名很簡(jiǎn)單,例如:

          												
          														
          																?

          												
          														
          																 public String myActionMethod() {

          												
          														
          																
          																		?? //..work

          												
          														
          																
          																		?? return "success";

          												
          														
          																 }

          												
          														
          																
          																
          														
          														
          																

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

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

          在這里需要特別指出的是, BeanAction 類(lèi)是對(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 類(lèi),位于 com.ibatis.struts 包下。正如上文所言,它是一個(gè)通用的控制類(lèi),利用反射機(jī)制,把控制轉(zhuǎn)移到 form bean 的某個(gè)方法來(lái)處理。詳細(xì)處理過(guò)程參考其源代碼,簡(jiǎn)單明晰。

          ·???????? Form bean 類(lèi)位于 com.ibatis.jpetstore.presentation 包下,命名規(guī)則為 ***Bean Form bean 類(lèi)全部繼承于 BaseBean 類(lèi),而 BaseBean 類(lèi)實(shí)際繼承于 ActionForm ,因此, Form bean 類(lèi)就是 Struts ActionForm Form bean 類(lèi)的屬性數(shù)據(jù)就由 struts 框架自動(dòng)填充。而實(shí)際上, JpetStore4.0 擴(kuò)展了 struts ActionForm 的應(yīng)用: Form bean 類(lèi)還具有行為,更像一個(gè) BO, 其行為(方法)由 BeanAction 根據(jù)配置( struts-config.xml )的 URL 來(lái)調(diào)用。雖然如此,我們還是把 Form bean 類(lèi)定位于表現(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 類(lèi)上的方法。 "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 類(lèi)位于 com.ibatis.jpetstore.service 包下,屬于業(yè)務(wù)層。這些類(lèi)封裝了業(yè)務(wù)以及相應(yīng)的事務(wù)控制。 Service 類(lèi)由 form bean 類(lèi)來(lái)調(diào)用。

          • com.ibatis.jpetstore.persistence.iface 包下的類(lèi)是 DAO 接口,屬于業(yè)務(wù)層,其屏蔽了底層的數(shù)據(jù)庫(kù)操作,供具體的 Service 類(lèi)來(lái)調(diào)用。 DaoConfig 類(lèi)是工具類(lèi)( DAO 工廠類(lèi)), Service 類(lèi)通過(guò) DaoConfig 類(lèi)來(lái)獲得相應(yīng)的 DAO 接口,而不用關(guān)心底層的具體數(shù)據(jù)庫(kù)操作,實(shí)現(xiàn)了如圖 2 { 耦合 2} 的解耦。

          • com.ibatis.jpetstore.persistence.sqlmapdao 包下的類(lèi)是對(duì)應(yīng) DAO 接口的具體實(shí)現(xiàn),在 JpetStore4.0 中采用了 ibatis 來(lái)實(shí)現(xiàn) ORM 。這些實(shí)現(xiàn)類(lèi)繼承 BaseSqlMapDao 類(lèi),而 BaseSqlMapDao 類(lèi)則繼承 ibatis DAO 框架中的 SqlMapDaoTemplate 類(lèi)。 ibatis 的配置文件存放在 com.ibatis.jpetstore.persistence.sqlmapdao.sql 目錄下。這些類(lèi)和配置文件位于數(shù)據(jù)層

          • Domain 類(lèi)位于 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 類(lèi)和 form bean 類(lèi)上,這也是其精華之一(雖然該實(shí)現(xiàn)方式是試驗(yàn)性,待擴(kuò)充和驗(yàn)證),在此次改造中我們要保留下來(lái),即控制層一點(diǎn)不變,表現(xiàn)層獲取相應(yīng)業(yè)務(wù)類(lèi)的方式變了(要加載 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)的方法改由自定義工廠類(lèi)來(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ī)制 , 采用自定義的工具類(lèi)( bean 工廠類(lèi))來(lái)加載 spring 的配置文件,從中可以看出 Spring 有多靈活,它提供了各種不同的方式來(lái)使用其不同的部分 / 層次,您只需要用你想用的,不需要的部分可以不用。

          具體的來(lái)說(shuō),就是在 com.ibatis.spring 包下創(chuàng)建 CustomBeanFactory 類(lèi), spring 的配置文件 applicationContext.xml 也放在這個(gè)目錄下。以下就是該類(lèi)的全部代碼,很簡(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) ,而不需要知道具體的類(lèi)。 CustomBeanFactory 類(lèi)用于 { 耦合 1} 的解耦。

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

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

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

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

          • presentation 類(lèi)僅僅面向 service 類(lèi)的接口編程,具體 "AccountService" 是哪個(gè)實(shí)現(xiàn)類(lèi), presentation 類(lèi)不知道,是在 spring 的配置文件里配置。(本例中,為了最大限度的保持原來(lái)的代碼不作變化,沒(méi)有抽象出接口)。 Spring 鼓勵(lì)面向接口編程,因?yàn)槭侨绱说姆奖愫妥匀唬?dāng)然您也可以不這么做。

          • CustomBeanFactory 這個(gè)工廠類(lèi)為什么會(huì)如此簡(jiǎn)單,因?yàn)槠渲苯邮褂昧?/span> Spring 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 ,以此作為其依賴(lài)注入機(jī)制的實(shí)現(xiàn)基礎(chǔ)。 org.springframework.beans 包中包括了這些核心組件的實(shí)現(xiàn)類(lèi),核心中的核心為 BeanWrapper BeanFactory 類(lèi)。

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


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

          1 、修改基類(lèi)

          所有的 DAO 實(shí)現(xiàn)類(lèi)都繼承于 BaseSqlMapDao 類(lèi)。修改 BaseSqlMapDao 類(lèi)如下:

          												
          														
          																?

          												
          														
          																public class BaseSqlMapDao extends SqlMapClientDaoSupport {

          												
          														
          																
          																		? protected static final int PAGE_SIZE = 4;

          												
          														
          																
          																		? protected SqlMapClientTemplate smcTemplate = this.getSqlMapClientTemplate();

          												
          														
          																
          																		? public BaseSqlMapDao() { 

          												
          														
          																
          																		???????? }

          												
          														
          																}

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

          2 、修改 DAO 實(shí)現(xiàn)類(lèi)

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

          												
          														
          																?

          												
          														
          																
          																		??? 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 、除去工廠類(lèi)以及相應(yīng)的配置文件

          除去 DaoConfig.java 這個(gè) DAO 工廠類(lèi)和相應(yīng)的配置文件 dao.xml ,因?yàn)?/font> DAO 的獲取現(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:com\ibatis\jpetstore\persistence\sqlmapdao\sql\sql-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 的值類(lèi)似于 "jdbc:oracle:thin:@wugfMobile:1521:cdcf" 。數(shù)據(jù)源現(xiàn)在由 spring 來(lái)管理,那么現(xiàn)在我們就可以去掉 properties 目錄下 database.properties 這個(gè)配置文件了;還有不要忘記修改 sql-map-config.xml ,去掉 <properties resource="properties/database.properties"/> 對(duì)它的引用。

          2. sqlMapClient 節(jié)點(diǎn)。這個(gè)是針對(duì) ibatis SqlMap SqlMapClientFactoryBean 配置。實(shí)際上配置了一個(gè) sqlMapClient 的創(chuàng)建工廠類(lèi)。 configLocation 屬性配置了 ibatis 映射文件的名稱(chēng)。 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)類(lèi)是 com.ibatis.jpetstore.persistence.sqlmapdao.AccountSqlMapDao ,使用的 SQL 配置從 sqlMapClient 中讀取,數(shù)據(jù)庫(kù)連接沒(méi)有特別列出,那么就是默認(rèn)使用 sqlMapClient 配置的數(shù)據(jù)源 datasource

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

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


          在這個(gè)例子中只有 3 個(gè)業(yè)務(wù)類(lèi),我們以 OrderService 類(lèi)為例來(lái)改造,這個(gè)類(lèi)是最復(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)類(lèi)是 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ù)性的方法被攔截。

          2 、業(yè)務(wù)類(lèi)的修改

          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è)置依賴(lài)注入,所以我們只需要定義屬性和相應(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ì)象的依賴(lài)注入,一致的數(shù)據(jù)存取框架和聲明式的事務(wù)處理,統(tǒng)一的配置文件…更重要的是 Spring 既是全面的又是模塊化的, Spring 有分層的體系結(jié)構(gòu),這意味著您能選擇僅僅使用它任何一個(gè)獨(dú)立的部分,就像本文,而它的架構(gòu)又是內(nèi)部一致。

          參考資料

          ??????作者Blog:http://blog.csdn.net/yanwp/

          posted on 2006-04-21 14:47 渠上月 閱讀(350) 評(píng)論(0)  編輯  收藏 所屬分類(lèi): java tips
          主站蜘蛛池模板: 丰顺县| 汽车| 垦利县| 闻喜县| 晋中市| 桦南县| 上思县| 洮南市| 临桂县| 永安市| 临清市| 汝城县| 武隆县| 西吉县| 青田县| 吴川市| 眉山市| 巧家县| 韩城市| 堆龙德庆县| 将乐县| 晋江市| 奈曼旗| 平凉市| 保靖县| 屏南县| 阜平县| 恭城| 江永县| 连城县| 小金县| 阳城县| 泸州市| 房产| 延津县| 东辽县| 上杭县| 湖北省| 永州市| 永兴县| 六安市|