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