<rt id="bn8ez"></rt>
<label id="bn8ez"></label>

  • <span id="bn8ez"></span>

    <label id="bn8ez"><meter id="bn8ez"></meter></label>

    隨筆 - 251  文章 - 504  trackbacks - 0
    <2006年11月>
    2930311234
    567891011
    12131415161718
    19202122232425
    262728293012
    3456789

    本博客系個人收集材料及學習記錄之用,各類“大俠”勿擾!

    留言簿(14)

    隨筆分類

    收藏夾

    My Favorite Web Sites

    名Bloger

    非著名Bloger

    搜索

    •  

    積分與排名

    • 積分 - 204336
    • 排名 - 283

    最新評論

      再譯:使用struts+spring+hibernate?組裝web應用
      原作者:?Mark?Eagle 04/07/2004(http://www.onjava.com/pub/a/onjava/2004/04/07/wiringwebapps.html?)
      譯者:孟大興 來自學習日記(?http://www.learndiary.com?) 聯(lián)系方式:mdx-xx@tom.com
      [譯者前言:這篇文章由totodo在2004-09-16已經(jīng)翻譯過(?http://www.matrix.org.cn/resource/article/1034.html?),本譯文借鑒了不少他的成果。希望各位朋友指出我譯文中的不足,并能根據(jù)上面的聯(lián)系方式及時反饋給我,我將第一時間內(nèi)在Matrix我的blog中更新譯文(?http://blog.matrix.org.cn/page/littlebat?entry=%E5%86%8D%E8%AF%91_%E4%BD%BF%E7%94%A8struts_spring_hibernate_%E7%BB%84%E8%A3%85web%E5%BA%94%E7%94%A8?),爭取為廣大不熟悉英文的朋友提供盡可能準確的譯文。另外,如果你在運行本文章的例程時碰到問題:請參考:1、原作者的網(wǎng)站上的答疑(?http://www.onjava.com/pub/a/onjava/2004/04/07/wiringwebapps.html?page=3?);2、我的試驗文中的例程的日記(?http://www.learndiary.com/disDiaryContentAction.do?goalID=1468?和?http://www.learndiary.com/disDiaryContentAction.do?goalID=1470?)]?

      其實,就算用Java建造一個不是很煩瑣的web應用程序,也不是件輕松的事情。當為一個應用程序建造一個構(gòu)架時有許多事情需要考慮。從高層來說,開發(fā)者需要考慮:怎樣建立用戶接口(?user?interfaces?)?在哪里處理業(yè)務邏輯?和怎樣持久化應用數(shù)據(jù)。這三層每一層都有它們各自的問題需要回答。?各個層次應該使用什么技術(shù)?怎樣才能把應用程序設計得松耦合和能靈活改變?構(gòu)架允許層的替換不會影響到其它層嗎?應用程序怎樣處理容器級的服務(?container?level?services?),比如事務處理(?transactions?)??

      當為你的web應用程序創(chuàng)建一個構(gòu)架時,需要涉及到相當多的問題。幸運的是,已經(jīng)有不少開發(fā)者已經(jīng)遇到過這類重復發(fā)生的問題,并且建立了處理這類問題的框架。一個好框架具備以下幾點:減輕開發(fā)者處理復雜的問題的負擔(?“不重復發(fā)明輪子”?);內(nèi)部定義為可擴展的;有一個強大的用戶群支持。框架通常能夠很好的解決一方面的問題。然而,你的應用程序有幾個層可能都需要它們各自的框架。就如解決你的用戶接口(?UI?)問題時你就不應該把事務邏輯和持久化邏輯摻雜進來。例如,你不應該在控制器(?controller?)里面寫jdbc代碼,使它包含有業(yè)務邏輯,這不是控制器應該提供的功能。它應該是輕量級的,代理來自用戶接口(?UI?)外的調(diào)用請求給其它服務于這些請求的應用層。好的框架自然的形成代碼如何分布的指導。更重要的是,框架減輕開發(fā)者從頭開始寫像持久層這樣的代碼的痛苦,使他們專注于對客戶來說很重要的應用邏輯。?

      這篇文章將討論怎樣組合幾個著名的框架去做到松耦合的目的,怎樣建立你的構(gòu)架,怎樣讓你的各個應用層保持一致。富于挑戰(zhàn)的是:組合這些框架使得每一層都以一種松耦合的方式彼此溝通,而與底層的技術(shù)無關(guān)。這篇文章將使用3種流行的開源框架來討論組合框架的策略。表現(xiàn)層我們將使用Struts(?http://jakarta.apache.org/struts?);業(yè)務層我們將使用Spring(?http://www.springframework.org/?);持久層使用Hibrenate(?http://www.hibernate.org/?).你也可以在你的應用程序中替換這些框架中的任何一種而得到同樣的效果。圖1展示了當這些框架組合在一起時從高層看是什么樣子。?

    圖1用Struts,?Spring,?和?Hibernate框架構(gòu)建的概覽?(?http://www.onjava.com/onjava/2004/04/07/graphics/wiring.gif?)


    應用程序的分層?(?Application?Layering?)
    大多數(shù)不復雜的web應用都能被分成至少4個各負其責的層次。這些層次是:表現(xiàn)層(?presentation?)、持久層(?persistence?)、業(yè)務層(?business?)、領域模型層(?domain?model?)。每層在應用程序中都有明確的責任,不應該和其它層混淆功能。每一應用層應該彼此獨立但要給他們之間放一個通訊接口。讓我們從審視各個層開始,討論這些層應該提供什么和不應該提供什么。?

    表現(xiàn)層?(The?Presentation?Layer)?

      在一個典型的web應用的一端是表現(xiàn)層。很多Java開發(fā)者也理解Struts所提供的。然而,太常見的是,他們把像業(yè)務邏輯之類的耦合的代碼放進了一個org.apache.struts.Action。所以,讓我們在像Struts這樣一個框架應該提供什么上取得一致意見。這兒是Struts負責的:?

    為用戶管理請求和響應;?
    提供一個控制器(?controller?)代理調(diào)用業(yè)務邏輯和其它上層處理;?
    處理從其它層擲出給一個Struts?Action的異常;?
    為顯示提供一個模型;?
    執(zhí)行用戶接口(?UI?)驗證。?

    這兒是一些經(jīng)常用Struts編寫的但是卻不應該和Struts表現(xiàn)層相伴的項目:?
    直接和數(shù)據(jù)庫通訊,比如JDBC調(diào)用;?
    業(yè)務邏輯和與你的應用程序相關(guān)的驗證;?
    事務管理;
    在表現(xiàn)層中引入這種代碼將導致典型耦合(?type?coupling?)和討厭的維護。?

    持久層?(?The?Persistence?Layer?)
    在典型web應用的另一端是持久層。這通常是使事情迅速失控的地方。開發(fā)者低估了構(gòu)建他們自己的持久層框架的挑戰(zhàn)性。一般來說,機構(gòu)內(nèi)部自己寫的持久層不僅需要大量的開發(fā)時間,而且還經(jīng)常缺少功能和變得難以控制。有幾個開源的“對象-關(guān)系映射”(?ORM?)框架非常解決問題。尤其是,Hibernate框架為java提供了"對象-關(guān)系持久化"(?object-to-relational?persistence?)機制和查詢服務。Hibernate對那些已經(jīng)熟悉了SQL和JDBC?API的Java開發(fā)者有一個適中的學習曲線。Hibernate持久對象是基于簡單舊式Java對象(?POJO?)和Java集合(?Java?collections?)。此外,使用Hibernate并不妨礙你正在使用的IDE。下面的列表包含了你該寫在一個持久層框架里的代碼類型:?

    查詢相關(guān)的信息成為對象。Hibernate通過一種叫作HQL的面向?qū)ο螅?OO?)的查詢語言或者使用條件表達式API(?expressive?criteria?API?)來做這個事情。?HQL非常類似于SQL--?只是把SQL里的table和columns用Object和它的fields代替。有一些新的專用的HQL語言成分要學;不過,它們?nèi)菀桌斫舛椅臋n做得好。HQL是一種使用來查詢對象的自然語言,花很小的代價就能學習它。?

    保存、更新、刪除儲存在數(shù)據(jù)庫中的信息。?

    像Hibernate這樣的高級“對象-關(guān)系”映射(?object-to-relational?mapping?)框架提供對大多數(shù)主流SQL數(shù)據(jù)庫的支持,它們支持“父/子”(?parent/child?)關(guān)系、事務處理、繼承和多態(tài)。?

    這兒是一些應該在持久層里被避免的項目:?

    業(yè)務邏輯應該在你的應用的一個高一些的層次里。持久層里僅僅允許數(shù)據(jù)存取操作。?

    你不應該把持久層邏輯(?persistence?logic?)和你的表現(xiàn)層邏輯(?presentation?logic?)攪在一起。避免像JSPs或基于servlet的類這些表現(xiàn)層組件里的邏輯和數(shù)據(jù)存取直接通訊。通過把持久層邏輯隔離進它自己的層,應用程序變得易于修改而不會影響在其它層的代碼。例如:Hebernate能夠被其它持久層框架或者API代替而不會修改在其它任何層的代碼。?

    業(yè)務層(?The?Business?Layer?)?

    在一個典型的web應用程序的中間的組件是業(yè)務層或服務層。從編碼的視角來看,這個服務層是最容易被忽視的一層。不難在用戶接口(?UI?)層或者持久層里找到散布在其中的這種類型的代碼。這不是正確的地方,因為這導致了應用程序的緊耦合,這樣一來,隨著時間推移代碼將很難維護。幸好,針對這一問題有好幾種Frameworks存在。在這個領域兩個最流行的框架是Spring和PicoContainer,它們叫作微容器(?microcontainers?),你可以不費力不費神的把你的對象連在一起。所有這些框架都工作在一個簡單的叫作“依賴注入”(?dependency?injection?)(?也通稱“控制反轉(zhuǎn)”(?inversion?of?control?)?)的概念上。這篇文章將著眼于Spring的為指定的配置參數(shù)通過bean屬性的setter注入(?setter?injection?)的使用。Spring也提供了一個構(gòu)建器注入(?constructor?injection?)的復雜形式作為setter注入的一個替代。對象們被一個簡單的XML文件連在一起,這個XML文件含有到像事務管理器(?transaction?management?handler?)、對象工廠(?object?factories?)、包含業(yè)務邏輯的服務對象(?service?objects?)、和數(shù)據(jù)存取對象(?DAO?)這些對象的引用(?references?)。?

    這篇文章的后面將用例子來把Spring使用這些概念的方法說得更清楚一些。業(yè)務層應該負責下面這些事情:?
    處理應用程序的業(yè)務邏輯和業(yè)務驗證;?
    管理事務;?
    預留和其它層交互的接口;?
    管理業(yè)務層對象之間的依賴;?
    增加在表現(xiàn)層和持久層之間的靈活性,使它們互不直接通訊;?
    從表現(xiàn)層中提供一個上下文(?context?)給業(yè)務層獲得業(yè)務服務(?business?services?);?
    管理從業(yè)務邏輯到持久層的實現(xiàn)。

    領域模型層?(?The?Domain?Model?Layer?)?
    最后,因為我們討論的是一個不是很復雜的、基于web的應用程序,我們需要一組能在不同的層之間移動的對象。領域?qū)ο髮佑赡切┐憩F(xiàn)實世界中的業(yè)務對象的對象們組成,比如:一份訂單(?Order?)、訂單項(?OrderLineItem?)、產(chǎn)品(?Product?)等等。這個層讓開發(fā)者停止建立和維護不必要的數(shù)據(jù)傳輸對象(?或者叫作DTOs?),來匹配他們的領域?qū)ο蟆@纾琀ibernate允許你把數(shù)據(jù)庫信息讀進領域?qū)ο螅?domain?objects?)的一個對象圖,這樣你可以在連接斷開的情況下把這些數(shù)據(jù)顯示到UI層。那些對象也能被更新和送回到持久層并在數(shù)據(jù)庫里更新。而且,你不必把對象轉(zhuǎn)化成DTOs,因為DTOs在不同的應用層間移動,可能在轉(zhuǎn)換中丟失。這個模型使得Java開發(fā)者自然地以一種面向?qū)ο蟮娘L格和對象打交道,沒有附加的編碼。?

    結(jié)合一個簡單的例子
      既然我們已經(jīng)從一個高的層次上理解了這些組件,?現(xiàn)在就讓我們開始實踐吧。在這個例子中,我們還是將合并Struts、Spring、Hibernate框架。每一個這些框架在一篇文章中都有太多的細節(jié)覆蓋到。這篇文章將用一個簡單的例子代碼展示怎樣把它們結(jié)合在一起,而不是進入每個框架的許多細節(jié)。示例應用程序?qū)⑹痉兑粋€請求怎樣跨越每一層被服務的。這個示例應用程序的一個用戶能保存一個訂單到數(shù)據(jù)庫中和查看一個在數(shù)據(jù)庫中存在的訂單。進一步的增強可以使用戶更新或刪除一個存在的訂單。  

    你可以下載這個應用的源碼(?http://www.onjava.com/onjava/2004/04/07/examples/wiring.zip?)。

      因為領域?qū)ο螅?domain?objects?)將和每一層交互,我們將首先創(chuàng)建它們。這些對象將使我們定義什么應該被持久化,什么業(yè)務邏輯應該被提供,和哪種表現(xiàn)接口應該被設計。然后,我們將配置持久層和用Hibernate為我們的領域?qū)ο螅?domain?objects?)定義“對象-關(guān)系”映射(?object-to-relational?mappings?)。然后,我們將定義和配置我們的業(yè)務對象(?business?objects?)。在有了這些組件后,我們就能討論用Spring把這些層連在一起。最后,我們將提供一個表現(xiàn)層(?presentation?layer?),它知道怎樣和業(yè)務服務層(?business?service?layer?)交流和知道怎樣處理從其它層產(chǎn)生的異常(?exceptions?)。

    領域?qū)ο髮樱?Domain?Object?Layer?)?
    因為這些對象將和所有層交互,這也許是一個開始編碼的好地方。這個簡單的領域模型將包括一個代表一份訂單(?order?)的對象和一個代表一個訂單項(?line?item?for?an?order?)的對象。訂單(?order?)對象將和一組訂單項(?a?collection?of?line?item?)對象有一對多(?one-to-many?)的關(guān)系。例子代碼在領域?qū)佑袃蓚€簡單的對象:
    com.meagle.bo.Order.java:?包括一份訂單(?oder?)的概要信息;
    com.meagle.bo.OrderLineItem.java:?包括一份訂單(?order?)的詳細信息;
    考慮一下為你的對象選擇包名,它將反映你的應用程序是怎樣分層的。例如:簡單應用的領域?qū)ο螅?domain?objects?)可以放進com.meagle.bo包[譯者注:bo-business?object?]。更多專門的領域?qū)ο髮⒎湃朐赾om.meagle.bo下面的子包里。業(yè)務邏輯在com.meagle.service包里開始打包,DAO對象放進com.meagle.service.dao.hibernate包。對于forms和actions的表現(xiàn)類(?presentation?classes?)分別放入com.meagle.action?和?com.meagle.forms包。準確的包命名為你的類提供的功能提供一個清楚的區(qū)分,使當故障維護時更易于維護,和當給應用程序增加新的類或包時提供一致性。

    持久層配置(?Persistence?Layer?Configuration?)?
    用Hibernate設置持久層涉及到幾個步驟。第一步是進行配置持久化我們的領域業(yè)務對象(?domain?business?objects?)。因為我們用于領域?qū)ο螅?domain?objects?)持久化的Hibernate和POJOs一起工作(?此句原文:Since?Hibernate?works?with?POJOs?we?will?use?our?domain?objects?for?persistence.?),因此,訂單和訂單項對象包括的所有的字段的都需要提供getter和setter方法。訂單對象將包括像ID、用戶名、合計、和訂單項這樣一些字段的標準的JavaBean格式的setter和getter方法。訂單項對象將同樣的用JavaBean的格式為它的字段設置setter和getter方法。
      Hibernate在XML文件里映射領域?qū)ο蟮疥P(guān)系數(shù)據(jù)庫。訂單和訂單項對象將有兩個映射文件來表達這種映射。有像XDoclet(?http://xdoclet.sourceforge.net/?)這樣的工具來幫助這種映射。Hibernate將映射領域?qū)ο蟮竭@些文件:
    Order.hbm.xml?
    OrderLineItem.hbm.xml?
    你可以在WebContent/WEB-INF/classes/com/meagle/bo目錄里找到這些生成的文件。配置Hibernate?SessionFactory(?http://www.hibernate.org/hib_docs/api/net/sf/hibernate/SessionFactory.html?)使它知道是在和哪個數(shù)據(jù)庫通信,使用哪個數(shù)據(jù)源或連接池,加載哪些持久對象。SessionFactory提供的Session(?http://www.hibernate.org/hib_docs/api/net/sf/hibernate/Session.html?)對象是Java對象和像選取、保存、更新、刪除對象這樣一些持久化功能間的翻譯接口。我們將在后面的部分討論Hibernate操作Session對象需要的SessionFactory配置。?
    業(yè)務層配置(?Business?Layer?Configuration?)
      既然我們已經(jīng)有了領域?qū)ο螅?domain?objects?),我們需要有業(yè)務服務對象來執(zhí)行應用邏輯、執(zhí)行向持久層的調(diào)用、獲得從用戶接口層(?UI?layer?)的請求、處理事務、處理異常。為了將所有這些連接起來并且易于管理,我們將使用Spring框架的bean管理方面(?bean?management?aspect?)。Spring使用“控制反轉(zhuǎn)”(?IoC?),或者“setter依賴注入”來把這些對象連好,這些對象在一個外部的XML文件中被引用。“控制反轉(zhuǎn)”是一個簡單的概念,它允許對象接受其它的在一個高一些的層次被創(chuàng)建的對象。使用這種方法,你的對象從必須創(chuàng)建其它對象中解放出來并降低對象耦合。

      這兒是個不使用IoC的對象創(chuàng)建它的從屬對象(?object?creating?its?dependencies?without?IoC?)的例子,這導致緊的對象耦合:
      圖2:沒有使用IoC的對象組織。對象A創(chuàng)建對象B和C(?http://www.onjava.com/onjava/2004/04/07/graphics/nonioc.gif?)。
      這兒是一個使用IoC的例子,它允許對象在一個高一些層次被創(chuàng)建和傳進另外的對象,所以另外的對象能直接使用現(xiàn)成的對象?[譯者注:另外的對象不必再親自創(chuàng)建這些要使用的對象](?allows?objects?to?be?created?at?higher?levels?and?passed?into?objects?so?that?they?can?use?the?implementations?directly?):
      圖3:對象使用IoC組織。對象A包含setter方法,它們接受到對象B和C的接口。這也可以用對象A里的接受對象B和C的構(gòu)建器完成(?http://www.onjava.com/onjava/2004/04/07/graphics/ioc.gif?)。

    建立我們的業(yè)務服務對象(?Building?Our?Business?Service?Objects?)?
      我們將在我們的業(yè)務對象中使用的setter方法接受的是接口,這些接口允許對象的松散定義的實現(xiàn),這些對象將被設置或者注入。在我們這個例子里我們將使我們的業(yè)務服務對象接受一個DAO去控制我們的領域?qū)ο蟮某志没.斘覀冊谶@篇文章的例子中使用Hibernate(?While?the?examples?in?this?article?use?Hibernate?),我們可以容易的轉(zhuǎn)換到一個不同的持久框架的實現(xiàn),通知Spring使用新的實現(xiàn)的DAO對象。你能明白編程到接口和使用“依賴注入”模式是怎樣寬松耦合你的業(yè)務邏輯和你的持久化機制的。
      這兒是業(yè)務服務對象的接口,它是一個DAO對象依賴的樁。(?Here?is?the?interface?for?the?business?service?object?that?is?stubbed?for?a?DAO?object?dependency:?)

    public?interface?IOrderService?{?
    public?abstract?Order?saveNewOrder(Order?order)?
    throws?OrderException,?
    OrderMinimumAmountException;?

    public?abstract?List?findOrderByUser(?
    String?user)?
    throws?OrderException;?

    public?abstract?Order?findOrderById(int?id)?
    throws?OrderException;?

    public?abstract?void?setOrderDAO(?
    IOrderDAO?orderDAO);?
    }?

      注意上面的代碼有一個為DAO對象準備的setter方法。這兒沒有一個getOrderDAO方法因為它不是必要的,因為不太有從外面訪問連著的OrderDAO對象的需要。DAO對象將被用來和我們的持久層溝通。我們將用Spring把業(yè)務服務對象和DAO對象連在一起。因為我們編碼到接口,我們不會緊耦合實現(xiàn)。

    下一步是寫我們的DAO實現(xiàn)對象。因為Spring有內(nèi)建的對Hibernate的支持,這個例子DAO將繼承HibernateDaoSupport(?http://www.springframework.org/docs/api/org/springframework/orm/hibernate/support/HibernateDaoSupport.html?)類,這使得我們?nèi)菀兹〉靡粋€到HibernateTemplate(?http://www.springframework.org/docs/api/org/springframework/orm/hibernate/HibernateTemplate.html?)類的引用,HibernateTemplate是一個幫助類,它能簡化Hibernate?Session的編碼和處理HibernateExceptions。這兒是DAO的接口:

    public?interface?IOrderDAO?{?

    public?abstract?Order?findOrderById(?
    final?int?id);?

    public?abstract?List?findOrdersPlaceByUser(?
    final?String?placedBy);?

    public?abstract?Order?saveOrder(?
    final?Order?order);?
    }?

      我們還有兩個對象要和我們的業(yè)務層連在一起。這包括HibernateSessionFactory和一個TransactionManager對象。這在Spring配置文件里直接完成。Spring提供一個HibernateTransactionManager(?http://www.springframework.org/docs/api/org/springframework/orm/hibernate/HibernateTransactionManager.html?),它將從工廠綁定一個Hibernate?Session到一個線程來支持事務(?見ThreadLocal(?http://java.sun.com/j2se/1.4.2/docs/api/java/lang/ThreadLocal.html?)獲取更多的信息?)。這兒是HibernateSessionFactory和HibernateTransactionManager的Spring配置。
    class="org.springframework.orm.hibernate.LocalSessionFactoryBean">?

    com/meagle/bo/Order.hbm.xml?

    com/meagle/bo/OrderLineItem.hbm.xml?

    net.sf.hibernate.dialect.MySQLDialect?

    false?

    C:/MyWebApps/.../WEB-INF/proxool.xml?

    spring?

    class="org.springframework.orm.hibernate.HibernateTransactionManager">?

      每一個對象能被Spring配置里的一個標記引用。在這個例子里,bean?“mySessionFactory”代表一個HibernateSessionFactory,bean?“myTransactionManager”代表一個Hibernate?transaction?manager。注意transactionManger?bean有一個叫作sessionFactory的屬性元素。HibernateTransactionManager有一個為sessionFactory準備的setter和getter方法,它們是用來當Spring容器啟動時的依賴注入。sessionFactory屬性引用mySessionFactory?bean。這兩個對象現(xiàn)在當Spring容器初始化時將被連在一起。這種連接把你從為引用和創(chuàng)建這些對象而創(chuàng)建singleton對象和工廠中解放出來,這減少了你應用程序中的代碼維護。mySessionFactory?bean有兩個屬性元素,它們翻譯成為mappingResources?和?hibernatePropertes準備的setter方法。通常,如果你在Spring之外使用Hibernate,這個配置將被保存在hibernate.cfg.xml文件中。不管怎樣,Spring提供了一個便捷的方式--在Spring配置文件中合并Hibernate的配置。獲得更多的信息查閱Spring?API(?http://www.springframework.org/docs/api/index.html?)。

    既然我們已經(jīng)配置了我們的容器服務beans和把它們連在了一起,我們需要把我們的業(yè)務服務對象和我們的DAO對象連在一起。然后,我們需要把這些對象連接到事務管理器。

    這是在Spring配置文件里的樣子:

    class="org.springframework.transaction.interceptor.TransactionProxyFactoryBean">

    PROPAGATION_REQUIRED,readOnly,-OrderException

    PROPAGATION_REQUIRED,-OrderException?

    class="com.meagle.service.spring.OrderServiceSpringImpl">?

    class="com.meagle.service.dao.hibernate.OrderHibernateDAO">?

    圖4是我們已經(jīng)連在一起的東西的一個概覽。它展示了每個對象是怎樣相關(guān)聯(lián)的和怎樣被Spring設置進其它對象中。把這幅圖和示例應用中的Spring配置文件對比查看它們之間的關(guān)系。

    圖4:這是Spring怎樣將在這個配置的基礎上裝配beans(?http://www.onjava.com/onjava/2004/04/07/graphics/spring_wiring.gif?)。

      這個例子使用一個TransactionProxyFactoryBean,它有一個為我們已經(jīng)定義了的事務管理者準備的setter方法。這是一個有用的對象,它知道怎樣處理聲明的事務操作和你的服務對象。你可以通過transactionAttributes屬性定義事務怎樣被處理,transactionAttributes屬性為方法名定義模式和它們怎樣參與進一個事務。獲得更多的關(guān)于在一個事務上配置隔離層和提交或回滾查閱TransactionAttributeEditor(?http://www.springframework.org/docs/api/org/springframework/transaction/interceptor/TransactionAttributeEditor.html?)。

      TransactionProxyFactoryBean(?http://www.springframework.org/docs/api/org/springframework/transaction/interceptor/TransactionProxyFactoryBean.html?)類也有一個為一個target準備的setter,target將是一個到我們的叫作orderTarget的業(yè)務服務對象的引用(?a?reference?)。?orderTarget?bean定義使用哪個業(yè)務服務對象并有一個指向setOrderDAO()的屬性。orderDAO?bean將居于這個屬性中,orderDAO?bean是我們的和持久層交流的DAO對象。

      還有一個關(guān)于Spring和bean要注意的是bean能以兩種模式工作。這兩種模式被定義為singleton和prototype。一個bean默認的模式是singleton,意味著一個共享的bean的實例將被管理。這是用于無狀態(tài)操作--像一個無狀態(tài)會話bean將提供的那樣。當bean由Spring提供時,prototype模式允許創(chuàng)建bean的新實例。你應當只有在每一個用戶都需要他們自己的bean的拷貝時才使用prototype模式。

    提供一個服務定位器(?Providing?a?Service?Locator?)
      既然我們已經(jīng)把我們的服務和我們的DAO連起來了,我們需要把我們的服務暴露給其它層。通常是一個像使用Struts或Swing這樣的用戶接口層里的代碼來使用這個服務。一個簡單的處理方法是使用一個服務定位器模式的類從一個Spring上下文中返回資源。這也可以靠引用bean?ID通過Spring來直接完成。
      這兒是一個在Struts?Action中怎樣配置一個服務定位器的例子:

    public?abstract?class?BaseAction?extends?Action?{?

    private?IOrderService?orderService;?

    public?void?setServlet(ActionServlet?
    actionServlet)?{?
    super.setServlet(actionServlet);?
    ServletContext?servletContext?=?
    actionServlet.getServletContext();?

    WebApplicationContext?wac?=?
    WebApplicationContextUtils.?
    getRequiredWebApplicationContext(?
    servletContext);?

    this.orderService?=?(IOrderService)?
    wac.getBean("orderService");?
    }?

    protected?IOrderService?getOrderService()?{?
    return?orderService;?
    }?
    }?

    用戶接口層配置?(?UI?Layer?Configuration?)?
      示例應用的用戶接口層使用Struts框架。這兒我們將討論當為一個應用分層時和Struts相關(guān)的部分。讓我們從在struts-config.xml文件里檢查一個Action配置開始。
      

    type="com.meagle.action.SaveOrderAction"?
    name="OrderForm"?
    scope="request"?
    validate="true"?
    input="/NewOrder.jsp">?
    Save?New?Order?

    path="/NewOrder.jsp"?
    scope="request"?
    type="com.meagle.exception.OrderException"/>?

    path="/NewOrder.jsp"?
    scope="request"?
    type="com.meagle.exception.OrderMinimumAmountException"/>

      SaveNewOrder?Action被用來持久化一個用戶從用戶接口層提交的訂單。這是一個典型的Struts?Action;然而,注意這個action的異常配置。這些Exceptions為我們的業(yè)務服務對象也在Spring?配置文件(applicationContext-hibernate.xml)中配置了(?在transactionAttributes屬性里?)。當這些異常被從業(yè)務層擲出我們能在我們的用戶接口里恰當?shù)奶幚硭鼈儭5谝粋€異常,OrderException,當在持久層里保存訂單對象失敗時將被這個action使用。這將引起事務回滾和通過業(yè)務對象傳遞把異常傳回給Struts層。OrderMinimumAmountException,在業(yè)務對象邏輯里的一個事務因為提交的訂單達不到最小訂單數(shù)量而失敗也將被處理。然后,事務將回滾和這個異常能被用戶接口層恰當?shù)奶幚怼?br />
      最后一個連接步驟是使我們的表現(xiàn)層和我們的業(yè)務層交互。這已經(jīng)通過使用前面討論的服務定位器來完成了。服務層充當一個到我們的業(yè)務邏輯和持久層的接口。這兒是?Struts中的SaveNewOrder?Action可能怎樣使用一個服務定位器調(diào)用一個業(yè)務方法:

    public?ActionForward?execute(?
    ActionMapping?mapping,?
    ActionForm?form,?
    javax.servlet.http.HttpServletRequest?request,?
    javax.servlet.http.HttpServletResponse?response)?
    throws?java.lang.Exception?{?

    OrderForm?oForm?=?(OrderForm)?form;?

    //?Use?the?form?to?build?an?Order?object?that?
    //?can?be?saved?in?the?persistence?layer.?
    //?See?the?full?source?code?in?the?sample?app.?

    //?Obtain?the?wired?business?service?object?
    //?from?the?service?locator?configuration?
    //?in?BaseAction.?
    //?Delegate?the?save?to?the?service?layer?and?
    //?further?upstream?to?save?the?Order?object.?
    getOrderService().saveNewOrder(order);?

    oForm.setOrder(order);?

    ActionMessages?messages?=?new?ActionMessages();?
    messages.add(?
    ActionMessages.GLOBAL_MESSAGE,?
    new?ActionMessage(?
    "message.order.saved.successfully"));?

    saveMessages(request,?messages);?

    return?mapping.findForward("success");?
    }?

    結(jié)論
      這篇文章按照技術(shù)和架構(gòu)覆蓋了許多話題。從中而取出的主要思想是怎樣更好的給你的應用程序分層:用戶接口層、持久邏輯層、和其它任何你需要的應用層。這樣可以解耦你的代碼,允許添加新的代碼組件,使你的應用在將來更易維護。這里覆蓋的技術(shù)能很好的解決這類的問題。不管怎樣,使用這樣的構(gòu)架可以讓你用其他技術(shù)代替現(xiàn)在的層。例如,你也許不想使用Hibernate持久化。因為你在你的DAO對象中編碼到接口,你能怎樣使用其它的技術(shù)或框架,比如?iBATIS(?http://www.ibatis.com/?),作為一個替代是顯而易見的。或者你可能用不同于Struts的框架替代你的UI層。改變UI層的實現(xiàn)不會直接影響你的業(yè)務邏輯層或者你的持久層。替換你的持久層不會影響你的UI邏輯或業(yè)務服務層。集成一個web應用其實也不是一件煩瑣的工作,靠解耦你的各應用層和用適當?shù)目蚣芙M成它,它能變得更容易處理。

    Mark?Eagle?是一位在MATRIX智囊團的高級軟件工程師,?Inc.?in?Atlanta,?GA。


    posted on 2006-11-20 15:10 matthew 閱讀(231) 評論(0)  編輯  收藏 所屬分類: JavaEE
    主站蜘蛛池模板: 一道本不卡免费视频| 成人性生交大片免费看午夜a| 91精品国产免费入口| 国产精品亚洲精品爽爽| 免费精品国产自产拍观看| 3d动漫精品啪啪一区二区免费| 免费手机在线看片| 亚洲av无码乱码国产精品fc2| 国产精品二区三区免费播放心| 久香草视频在线观看免费| 亚洲人精品亚洲人成在线| 热99re久久精品精品免费| **真实毛片免费观看| 永久免费av无码网站yy| 亚洲精品在线电影| 亚洲AV综合色一区二区三区| 在线看片人成视频免费无遮挡| 91在线老王精品免费播放| 国产中文字幕在线免费观看| 一级a性色生活片久久无少妇一级婬片免费放 | 亚洲一区精品无码| 免费在线观看亚洲| 日韩a级毛片免费观看| 中文精品人人永久免费| 特级做a爰片毛片免费看| 亚洲AV第一成肉网| 亚洲成AV人片在| 在线观看免费大黄网站| 67194熟妇在线永久免费观看| 无码人妻一区二区三区免费看| 99re6在线精品免费观看| 国产国产人免费人成成免视频| 91在线亚洲精品专区| 亚洲成色在线综合网站| 亚洲日韩乱码中文无码蜜桃臀网站| 亚洲一区无码精品色| 免费下载成人电影| japanese色国产在线看免费| 日本亚洲高清乱码中文在线观看 | 一级做a爱片特黄在线观看免费看 一级做a爱过程免费视 | 国产精品亚洲av色欲三区|