其實,就算用Java建造一個不是很煩瑣的web應用,也不是件輕松的事情。 在構架的一開始就有很多事情要考慮。 從高處看,擺在開發(fā)者面前有很多問題:要考慮是怎樣建立用戶接口?在哪里處理業(yè)務邏輯? 怎樣持久化的數(shù)據(jù)。 而這三層構架中,每一層都有他們要仔細考慮的。 各個層該使用什么技術? 怎樣的設計能松散耦合還能靈活改變? 怎樣替換某個層而不影響整體構架?應用程序如何做各種級別的業(yè)務處理(比如事務處理)?
構架一個Web應用需要弄明白好多問題。 幸運的是,已經有不少開發(fā)者已經遇到過這類問題,并且建立了處理這類問題的框架。 一個好框架具備以下幾點: 減輕開發(fā)者處理復雜的問題的負擔(“不重復發(fā)明輪子”); 內部有良好的擴展; 并且有一個支持它的強大的用戶團體。 好的構架一般有針對性的處理某一類問題,并且能將它做好(Do One Thing well)。 然而,你的程序中有幾個層可能需要使用特定的框架,已經完成的UI(用戶接口) 并不代表你也可以把你的業(yè)務邏輯和持久邏輯偶合到你的UI部分。 舉個例子, 你不該在一個Controller(控制器)里面寫JDBC代碼作為你的業(yè)務邏輯, 這不是控制器應該提供的。 一個UI 控制器應該委派給其它給在UI范圍之外的輕量級組件。 好的框架應該能指導代碼如何分布。 更重要的是,框架能把開發(fā)者從編碼中解放出來,使他們能專心于應用程序的邏輯(這對客戶來說很重要)。
這篇文章將討論怎樣結合幾種著名的框架來使得你的應用程序做到松弛耦合。
如何建立你的架構,并且怎樣讓你的各個應用層保持一致。?如何整合框架以便讓每個層在以一種松散偶合的方式彼此作用而不用管低層的技術細節(jié)?這對我們來說真是一種挑戰(zhàn)。 這里討論一個整合框架的策略( 使用3 種受歡迎的開源框架) :表示層我們用Struts; 業(yè)務層我們用Spring;而持久層則用Hibernate。 你也可以用其他FrameWork替換只要能得到同樣的效果。 見圖1 (框架組合示意圖)

應用程序的分層
大部分的Web應用在職責上至少能被分成4層。 這四層是:presentation(描述),persistence(持久),business(業(yè)務)和domain model(域模塊)。每個層在處理程序上都應該有一項明確的責任, 而不應該在功能上與其它層混合,并且每個層要與其它層分開的,但要給他們之間放一個通信接口。 我們就從介紹各個層開始,討論一下這些層應該提供什么,不應該提供什么。
表示層(The Presentation Layer)
一般來講,一個典型的Web應用的的末端應該是表示層。 很多Java發(fā)者也理解Struts所提供的。 象業(yè)務邏輯之類的被打包到org.apache.struts.Action., 因此,我們很贊成使用Struts這樣的框架。
下面是Struts所負責的:
* 管理用戶的請求,做出相應的響應。
* 提供一個Controller ,委派調用業(yè)務邏輯和其它上層處理。
* 處理異常,拋給Struts Action
* 為顯示提供一個模型
* UI驗證。
以下條款,不該在Struts顯示層的編碼中經常出現(xiàn)。 它們與顯示層無關的。
* 直接的與數(shù)據(jù)庫通信,例如JDBC調用。
* 與你應用程序相關聯(lián)的業(yè)務邏輯以及校驗。
* 事物管理。
在表示層引入這些代碼,則會帶來高偶合和麻煩的維護。
持久層(The Persistence Layer)
典型的Web應用的另一個末端是持久層。這里通常是程序最容易失控的地方。開發(fā)者總是低估構建他們自己的持久框架的挑戰(zhàn)性。系統(tǒng)內部的持續(xù)層不但需要大量調試時間,而且還經常缺少功能使之變得難以控制,這是持久層的通病。 還好有幾個ORM開源框架很好的解決了這類問題。尤其是Hibernate。 Hibernate為java提供了OR持久化機制和查詢服務, 它還給已經熟悉SQL和JDBC API 的Java開發(fā)者一個學習橋梁,他們學習起來很方便。 Hibernate的持久對象是基于POJO和Java collections。此外,使用Hibernate并不妨礙你正在使用的IDE。
請看下面的條目,你在持久層編碼中需要了解的。
* 查詢對象的相關信息的語句。 Hibernate通過一個OO查詢語言(HQL)或者正則表達的API來完成查詢。 HQL非常類似于SQL-- 只是把SQL里的table和columns用Object和它的fields代替。 你需要學習一些新的HQL語言; 不管怎樣,他們容易理解而文檔也做的很好。 HQL是一種對象查詢的自然語言,花很小的代價就能學習它。
* 如何存儲,更新,刪除數(shù)據(jù)庫記錄。
* 象Hibernate這類的高級ORM框架支持大部分主流數(shù)據(jù)庫,并且他們支持 Parent/child關系,事物處理,繼承和多態(tài)。
業(yè)務層(The Business Layer)
一個典型Web應用的中間部分是業(yè)務層或者服務層。 從編碼的視角來看,這層是最容易被忽視的一層。 而我們卻往往在UI層或持久層周圍看到這些業(yè)務處理的代碼,這其實是不正確的,因為它導致了程序代碼的緊密偶合,這樣一來,隨著時間推移這些代碼很難維護。幸好,針對這一問題有好幾種Frameworks存在。 最受歡迎的兩個框架是Spring和PicoContainer。 這些為也被稱為microcontainers,他們能讓你很好的把對象搭配起來。 這兩個框架都著手于‘依賴注射’(dependency injection)(還有我們知道的‘控制反轉’Inversion of Control=IoC)這樣的簡單概念。 這篇文章將關注于Spring的注射(譯注:通過一個給定參數(shù)的Setter方法來構造Bean,有所不同于Factory), Spring還提供了Setter Injection(type2),Constructor Injection(type3)等方式供我們選擇。 Spring把程序中所涉及到包含業(yè)務邏輯和Dao的Objects——例如transaction management handler(事物管理控制)、Object Factoris(對象工廠)、service objects(服務組件)——都通過XML來配置聯(lián)系起來。
后面我們會舉個例子來揭示一下Spring 是怎樣運用這些概念。
業(yè)務層所負責的如下:
* 處理應用程序的 業(yè)務邏輯和業(yè)務校驗
* 管理事物
* 允許與其它層相互作用的接口
* 管理業(yè)務層級別的對象的依賴。
* 在顯示層和持久層之間增加了一個靈活的機制,使得他們不直接的聯(lián)系在一起。
* 通過揭示 從顯示層到業(yè)務層之間的Context來得到business services。
* 管理程序的執(zhí)行(從業(yè)務層到持久層)。
域模塊層(The Domain Model Layer )
既然我們致力于的是一個不是很復雜的Web的應用, 我們需要一個對象集合,讓它在不同層之間移動的。 域模塊層由實際需求中的業(yè)務對象組成 比如, OrderLineItem , Product等等。 開發(fā)者在這層 不用管那些DTOs,僅關注domain object即可。 例如,Hibernate允許你將數(shù)據(jù)庫中的信息存放入對象(domain objects),這樣你可以在連接斷開的情況下把這些數(shù)據(jù)顯示到UI層。 而那些對象也可以返回給持續(xù)層,從而在數(shù)據(jù)庫里更新。 而且,你不必把對象轉化成DTOs(這可能似的它在不同層之間的在傳輸過程中丟失),這個模型使得Java開發(fā)者能很自然運用OO,而不需要附加的編碼。
一個簡單例子
既然我們已經從全局上理解這些組件。 現(xiàn)在就讓我們開始實踐吧。 我們還是用 Struts,Spring 和Hibernate。這三個框架已經被描述夠多了,這里就不重復介紹了。 這篇文章舉例指導你如何使用這三個框架整合開發(fā), 并向你揭示 一個請求是如何貫穿于各個層的。(從用戶的加入一個Order到數(shù)據(jù)庫,顯示;進而更新、刪除)。
從這里可以下載到程序程序原代碼(download)
既然每個層是互相作用的,我們就先來創(chuàng)建domain objects。首先,我們要在這些Object中要確定那些是需要持久化的,哪些是提供給business logic,那些是顯示接口的設計。 下一步,我們將配置我們的持久層并且定義好Hibernate的OR mappings。然后定義好Business Objects。有了這些組成部分之后,我們將 使用Spring把這些連接起來。 最后,我們提供給Spring一個持久層,從這個持久層里我們可以知道它是如何與業(yè)務邏輯層(business service layer)通信的,以及它是怎樣處理其他層拋出的異常的。。
域對象層(Domain Object Layer)
這層是編碼的著手點,我們的編碼就從這層開始。 例子中Order 與OrderItem 是一個One—To—Many的關系。 下面就是Domain Object Layer的兩個對象:
· com.meagle.bo.Order.java: 包含了一個Order的概要信息
· com.meagle.bo.OrderLineItem.java: 包含了Order的詳細信息
好好考慮怎你的package命名,這反應出了你是怎樣分層的。 例如 domain objects在程序中可能打包在com.meagle.bo
內。 更詳細一點將打包在com. meagle.bo
的子目錄下面。business logic應該從com.meagle.serice
開始打
包,而DAO 對象應該位于com.meagle.service.dao.hibernate
。反應
Forms
和
Actions
的
持久對象(
presentation classes) 應該分別放在 com.meagle.action
和
com.meagle.forms
包。 準確的給包命名使得你的classes很好分割并且易于維護,并且在你添加新的classes時,能使得程序結構上保持上下一致。
持久層的配置(Persistence Layer Configuration)
建立Hibernate的持久層 需要好幾個步驟。 第一步讓我們把BO持久化。 既然Hibernate是通過POJO工作的, 因此Order
和 OrderLineItem
對象需要給所有的fileds 加上getter,setter方法。 Hibernate通過XML文件來映射(OR)對象,以下兩個xml文件分別映射了Order 和OrderItem對象。(這里有個叫XDoclet工具可以自動生成你的XML影射文件)
- Order.hbm.xml
- OrderLineItem.hbm.xml
你可以在WebContent/WEB-INF/classes/com/meagle/bo目錄下找到這些xml文件。Hibernate的 SessionFactory 是用來告訴程序 應該與哪個數(shù)據(jù)庫通信,該使用哪個連接池或使用了DataSource
,
應該加載哪些持久對象。而Session接口是用來完成Selecting,Saving,Delete和Updating這些操作。 后面的我們將講述SessionFactory和Session是怎樣設置的。
業(yè)務層的配置(Business Layer Configuration)
既然我們已經有了domain objects,接下來我們就要business service objects了,用他們來執(zhí)行程序的logic,調用持久層,得到UI層的requests,處理transactions,并且控制exceptions。 為了將這些連接起來并且易于管理,我們將使用面向方面的 SpringFramework。 Spring 提供了 控制倒置(inversion of control 0==IoC)和注射依賴設置(setter dependency injection)這些方式(可供選擇),用XML文件將對象連接起來。 IoC是一個簡單概念(它允許一個對象在上層接受其他對象的創(chuàng)建),用IoC這種方式讓你的對象從創(chuàng)建中釋放了出來,降低了偶合度。
這里是一個沒有使用IoC的對象創(chuàng)建的例子,它有很高偶合度。

圖 2.沒有使用 IoC. A 創(chuàng)建了 B 和 C
而這里是一個使用IoC的例子,這種方式允許對象在高層可以創(chuàng)建并進入另外一個對象,所以這樣可以直接被執(zhí)行。

圖 3. 對象使用了 IoC。 A 包含了接受B,C的 setter方法 , 這同樣達到了 由A創(chuàng)建B,C的目的。
建立我們的業(yè)務服務對象(Building Our Business Service Objects)
Business Object中的Setter方法接受的是接口,這樣我們可以很松散的定義對象實現(xiàn),然后注入。 在我們的案例中,我們將用一個business service object接收一個DAO,用它來控制domain objects的持久化。 由于在這個例子中使用了Hibernate,我們可以很方便的用其他持久框架實現(xiàn) 同時通知Spring 有新的DAO可以使用了。
在面向接口的編程中,你會明白 “注射依賴”模式是怎樣松散耦合你的業(yè)務邏輯和持久機制的:)。
下面是一個接口business service object,DAO代碼片段:
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);
}
注意到這段代碼里有一個 setOrderDao(),它就是一個DAO Object設置方法(注射器)。 但這里并沒有一個getOrderDao的方法,這不必要,因為你并不會在外部訪問這個orderDao。這個DAO Objecte將被調用,和我們的persistence layer 通信。我們將用Spring把DAO Object 和 business service object搭配起來的。因為我們是面向接口編程的,所以并不需要將實現(xiàn)類緊密的耦合在一起。
接下去我們開始我們的DAO的實現(xiàn)類進行編碼。 既然Spring已經有對Hibernate的支持,那這個例子就直接繼承HibernateDaoSupport
類了,這個類很有用,我們可以參考HibernateTemplate
(它主要是針對HibernateDaoSupport的一個用法,譯注:具體可以查看Srping 的API)。 下面是這個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);
}
我們仍然要給我們持久層組裝很多關聯(lián)的對象,這里包含了HibernateSessionFactory
和TransactionManager
。
Spring 提供了一個 HibernateTransactionManager
,他用線程捆綁了一個Hibernate Session
本站是提供個人知識管理的網絡存儲空間,所有內容均由用戶發(fā)布,不代表本站觀點。請注意甄別內容中的聯(lián)系方式、誘導購買等信息,謹防詐騙。如發(fā)現(xiàn)有害或侵權內容,請點擊一鍵舉報。