|
在06、07年的時候,我寫過一些關(guān)于三層架構(gòu)方面的東西(參見這里),現(xiàn)在看來,覺得有很多實用性的內(nèi)容需要補充到里面去。我們還是先從架構(gòu)圖看起,然后一一解釋,你就會發(fā)現(xiàn)相比于兩年前,這個架構(gòu)做了哪些變化和調(diào)整。
一.三層架構(gòu)圖
二.系統(tǒng)各層次職責
1.UI(User Interface)層的職責是數(shù)據(jù)的展現(xiàn)和采集,數(shù)據(jù)采集的結(jié)果通常以Entity object提交給BL層處理。
Web表示我們常用的B/S應(yīng)用,WinForm表示我們常用的C/S應(yīng)用。
NETwork層以Socket的方式提供服務(wù)給客戶端。
Service層用于將業(yè)務(wù)或數(shù)據(jù)資源發(fā)布為服務(wù)(如WebServices)。
2.BL(Business Logic)&Platform層的職責是按預(yù)定的業(yè)務(wù)邏輯處理UI層提交的請求,并對核心資源進行管理。
(1)Business Function 子層負責基本業(yè)務(wù)功能的實現(xiàn)。
(2)Business Flow 子層負責將Business Function子層提供的多個基本業(yè)務(wù)功能組織成一個完整的業(yè)務(wù)流。
(3)Platform子層用于統(tǒng)一管理有狀態(tài)的數(shù)據(jù)和資源。
(4)注意:Transaction只能在BusinessFlow/Platform層開啟。
(5)BL最好是沒有狀態(tài)的,而必需的狀態(tài)管理可以放到Platform中的某些模塊/子系統(tǒng)進行。如此可增強系統(tǒng)的可伸縮性。
(6)Cache子層用于緩存系統(tǒng)常用的數(shù)據(jù)信息,Cache對于提供系統(tǒng)的并發(fā)量和吞吐能力起到至關(guān)重要的作用。Cache可以分為以下幾類:
StaticCache | HotCache | SyncEntityCache | RefreshCache | SubObjectCache |
StaticCache:如果某數(shù)據(jù)表中的數(shù)據(jù)是靜態(tài)的、不會發(fā)生變化的,那就非常容易,我們只需要在系統(tǒng)啟動的時候,將其加載到內(nèi)存,以后每次從內(nèi)存讀取數(shù)據(jù)即可。
HotCache:如果數(shù)據(jù)表中的記錄非常多,并且修改方面只會有Insert操作,那么我們可以使用HotCache,把那些經(jīng)常使用的記錄緩存在內(nèi)存中,并且可設(shè)定超時機制刪除內(nèi)存中長期不使用的記錄。
SyncEntityCache:如果我們的某個數(shù)據(jù)表中的數(shù)據(jù)會發(fā)生變化(增刪改),但是變化的頻率比較低,但是我們的系統(tǒng)對這個表的數(shù)據(jù)的實時性的敏感度也特別高,那這時候我們就需要用到【實時同步的實體緩存】,這個緩存中的數(shù)據(jù)在任何時候都與數(shù)據(jù)表中的數(shù)據(jù)是完全一致的。
RefreshCache:如果數(shù)據(jù)表中的數(shù)據(jù)會發(fā)生變化(增刪改),但是變化的頻率非常低,而恰巧我們的系統(tǒng)對數(shù)據(jù)實時性的敏感度也不是特別高,那我們可以使用定時刷新的緩存。
SubObjectCache:如果某個數(shù)據(jù)表的修改經(jīng)常是Insert和Update操作,但是無論如何Update,每條記錄有些固定欄位的值都是不會發(fā)生變化的,那我們可以把這些不會發(fā)生變化的欄位封裝在一個【子對象SubObject】中,然后在內(nèi)存中緩存這些子對象。
3.DataAccess層的職責是提供全面的資源訪問功能支持,并向上層屏蔽資源的來源。
BEM(Business Entity Manager)子層負責從數(shù)據(jù)庫中存取資源。
DB Adapter子層負責屏蔽數(shù)據(jù)庫類型的差異。
ORM子層負責提供對象-關(guān)系映射的功能。
Relation子層提供ORM無法完成的基于關(guān)系(Relation)的數(shù)據(jù)訪問功能。
4.Entity側(cè)層跨越UI/BL&Platform/DataAccess層,在這些層之間傳遞數(shù)據(jù)。Entity側(cè)層中包含三類Entity,如下圖所示:
5.DB層可以采用數(shù)據(jù)庫分散放置、讀寫分離策略來支持超大并發(fā)。圖中數(shù)據(jù)庫名稱,M代表Master(主庫),S代表Slave(從庫)。 6.Tools層,架構(gòu)圖中還一個虛線表示的Tools層,之所以用虛線,是因為它并不真的是系統(tǒng)交付的一部分,它并不實現(xiàn)系統(tǒng)的邏輯功能。但它的存在是如此的重要,特別是在我們的開發(fā)和測試階段。它的主要作用有: (1)DataMonitor:能將數(shù)據(jù)庫中最重要的信息方便的呈現(xiàn)給工程師,比如重要表和超大表的記錄數(shù)等。 (2)DataChecker:直接對數(shù)據(jù)庫中的數(shù)據(jù)進行完整性、一致性檢查。使我們能最及時的發(fā)現(xiàn)業(yè)務(wù)邏輯在數(shù)據(jù)處理方面的重大失誤和錯漏。 (3)DataRepairer:當發(fā)現(xiàn)了數(shù)據(jù)錯誤并對程序的bug進行修正后,Tools能夠?qū)?shù)據(jù)進行補充或修復(fù)。以使后續(xù)開發(fā)和測試能立即繼續(xù)進行。 ASPect貫穿于系統(tǒng)各層,是系統(tǒng)的橫切關(guān)注點。通常采用AOP技術(shù)來對橫切關(guān)注點進行建模和實現(xiàn)。 1.Securtiy ASPect:用于對整個系統(tǒng)的Security提供支持。 2.ErrorHandling ASPect:整個系統(tǒng)采用一致的錯誤/異常處理方式。 3.Log ASPect:用于系統(tǒng)異常、日志記錄、業(yè)務(wù)操作記錄等。 (1)通常我們會記錄相鄰兩層的交互接口所引發(fā)的所有異常的詳細信息,包括方法調(diào)用的堆棧幀、調(diào)用方法的參數(shù)的具體值。(參考這里) (2)通常我們會跟蹤相鄰兩層的交互接口的每個方法執(zhí)行所消耗的時間,用于檢查系統(tǒng)的性能瓶頸在哪些地方。(參考這里) (3)通常我們會記錄所有數(shù)據(jù)庫訪問異常的詳細信息,包括sql語句內(nèi)容、各參數(shù)的具體值。(參考這里) (4)在測試階段,通常我們會記錄所有每個事務(wù)訪問數(shù)據(jù)表的順序,通過對比這些順序,我們可以發(fā)現(xiàn)可能出現(xiàn)死鎖的地方,從而加以調(diào)整。(DataRabbit內(nèi)置支持) (5)另外,一些重要的作業(yè)操作我們也會記錄到日志。 1.系統(tǒng)各層次及層內(nèi)部子層次之間都不得跨層調(diào)用。 2.使用Entity object 在各個層之間傳遞數(shù)據(jù),而不是關(guān)系型的DataSet。只有在特殊情況下,才將UI綁定到DataTable,比如返回的結(jié)果集沒有Entity與之對應(yīng)的時候。 3.UI層和BL層禁止出現(xiàn)任何SQL語句。 4.對于每一個數(shù)據(jù)庫表(Table)都有一個DB Entity class與之對應(yīng),針對每一個Entity class都會有一個BEM Class與之對應(yīng)。 5.有些跨數(shù)據(jù)庫或跨表的操作(如復(fù)雜的聯(lián)合查詢)也需要由相應(yīng)的BEM Class來提供支持。 6.對于相對簡單的系統(tǒng),可以考慮將Business Function子層和Business Flow 子層合并為一個。 異常可以分為系統(tǒng)異常(如網(wǎng)絡(luò)突然斷開)和業(yè)務(wù)異常(如用戶的輸入值超出最大范圍),業(yè)務(wù)異常必須被轉(zhuǎn)化為業(yè)務(wù)執(zhí)行的結(jié)果。 1. DataAccess層不得向上層隱藏任何異常(該層拋出的異常幾乎都是系統(tǒng)異常)。 2. 要明確區(qū)分業(yè)務(wù)執(zhí)行的結(jié)果和系統(tǒng)異常。比如驗證用戶的合法性,如果對應(yīng)的用戶ID不存在,不應(yīng)該拋出異常,而是返回(或通過out參數(shù))一個表示驗證結(jié)果的枚舉值,這屬于業(yè)務(wù)執(zhí)行的結(jié)果。但是,如果在從數(shù)據(jù)庫中提取用戶信息時,數(shù)據(jù)庫連接突然斷開,則應(yīng)該拋出系統(tǒng)異常。 3. 在有些情況下,BL層應(yīng)根據(jù)業(yè)務(wù)的需要捕獲某些系統(tǒng)異常,并將其轉(zhuǎn)化為業(yè)務(wù)執(zhí)行的結(jié)果。比如,某個業(yè)務(wù)要求試探指定的數(shù)據(jù)庫是否可連接,這時BL就需要將數(shù)據(jù)庫連接失敗的系統(tǒng)異常轉(zhuǎn)換為業(yè)務(wù)執(zhí)行的結(jié)果。 4. UI層(包括Service層)除了從調(diào)用BL層的API獲取的返回值來查看業(yè)務(wù)的執(zhí)行結(jié)果外,還需要截獲所有的系統(tǒng)異常,并將其解釋為友好的錯誤信息呈現(xiàn)給用戶。 5. 當WebService的參數(shù)或返回值需要是復(fù)雜類型――即架構(gòu)圖中的Service Entity,則Service Entity應(yīng)該在對應(yīng)的*.EntranceParaDef.dll中定義。WebService定義的方法中的復(fù)雜類型應(yīng)該使用Xml字符串代替,而Xml字符串和復(fù)雜類型對象之間的轉(zhuǎn)換應(yīng)當在*.Entrance.dll中實現(xiàn)。 三.ASPect
四.規(guī)則
五.錯誤與異常
不知您有何補充或建議,請指點一二,呵呵。
it知識庫:我的架構(gòu)經(jīng)驗小結(jié)(四)-- 實戰(zhàn)中演化的三層架構(gòu),轉(zhuǎn)載需保留來源!
鄭重聲明:本文版權(quán)歸原作者所有,轉(zhuǎn)載文章僅為傳播更多信息之目的,如作者信息標記有誤,請第一時間聯(lián)系我們修改或刪除,多謝。