1. 程式人生 > >ABP原始碼分析十:Unit Of Work

ABP原始碼分析十:Unit Of Work

ABP以AOP的方式實現UnitOfWork功能。通過UnitOfWorkRegistrar將UnitOfWorkInterceptor在某個類被註冊到IOCContainner的時候,一併新增到該類在容器中對應的ComponentModelInterceptors集合中。總結一句話就是,UOW的功能是通過自定義Castle攔截器來實現的。本文主要介紹ABP核心框架中的UnitOfWork的實現,後續會分別介紹ABP其他模組是如何具體實現IUnitOfWork的

如圖,AbpKernelModule呼叫UnitOfWorkRegister的Initialize方法將UnitOfWorkInterceptor攔截器新增到標註了UnitOfWork特性

法的類,以及實現IRepository或IApplicationService的類上。

下圖是UnitOfWorkRegister的程式碼

和通常實現的AOP一樣,ABP定義了UnitOfWork特性,方便業務層為方法注入UOW功能。

UnitOfWorkAttribute:用於標註某個方法位UnitOfWorkAttribute. 通過這個特性,可以指定是否啟用UOW,事務隔離級別,TransactionScopeOption

UnitOfWorkOptions: 封裝了UnitOfWork引數的類,其例項是通過UnitOfWorkAttribute的CreateOptions來生成的。

接下來,分析下UnitOfWork是如何封裝事務的。

基於介面隔離原則的考量,ABP作者將UnitOfWork的方法分到了三個不同的介面中,如下圖。

IUnitOfWorkCompleteHandle:定義了UOW同步和非同步的complete方法。實現UOW完成時候的邏輯。

IActiveUnitOfWork:一個UOW除了以上兩個介面中定義的方法和屬性外,其他的屬性和方法都在這個介面定義的。比如Completed,Disposed,Failed事件代理,Filter的enable和disable,以及同步、非同步的SaveChanges方法。

IUnitOfWork

:繼承了上面兩個介面。定義了外層的IUnitOfWork的引用和UOW的begin方法。 ABP是通過構建一個UnitOfWork的鏈,將不同的方法納入到一個事務中(後文解釋)。

UnitOfWorkBase:這個抽象類實現了上面三個介面中定義的方法,而真正實現事務控制的方法是由這個抽象類的子類實現的(比如,真正建立TransactionScope的操作是在EfUnitOfWorkNhUnitOfWork這樣的之類中實現的)。UOW中除了事務控制邏輯以外的邏輯都是由UnitOfWorkBase抽象類實現的。

ABP中共有以下4個具體的UOW型別,他們都繼承自UnitOfWorkBase。Entity Framework, Nhibernate UnitOfWork是實現事務控制的UOW。MongoDB MemoryDB UnitOfWork是沒有事務控制的。 原因很簡單,MongoDB本身就沒有完整的事務控制功能, 而ABP 框架實現的MemoryDB也是沒有事務控制功能的。

IUnitOfWorkManager/UnitOfWorkManager:和其他***manager類一樣是一個Facade,他對外提供UOW的功能(用於建立UnitOfWork,並開啟UnitOfWork流程),對內呼叫各種UOW功能的各種元件。

UnitOfWork攔截器呼叫UnitOfWorkManager開啟UOW流程的程式碼。

Unit Of Work大致執行流程如下

  1. UOW攔截器被注入到需要UOW的類中。
  2. ABP執行標註了UnitOfWork特性的方法時。UOW攔截器以begin()->realAction()->complete()->dispose()順序執行,其中realAction是被呼叫的真實業務操作。 UOW攔截器是通過using這種方式呼叫IUnitOfWork的某個具體實現,這就確保begin dispose也總是會被執行的。 這裡需要注意complete不一定會被執行,比如在complete方法被呼叫前方法的執行產生了異常。
  3. 當執行一連串的操作時(A方法->B方法->C方法,假設這三個方法都標註了UnitOfWork特性),ABP在執行A方法前會建立整個過程中唯一的IUnitOfWork物件,該物件會啟動.NET事務。在執行到B,C方法只會建立InnerUnitOfWorkCompleteHandle。 InnerUnitOfWorkCompleteHandle與IUnitOfWork物件的差異在於它不會建立真實的事務。但ABP呼叫complete,以告知ABP其對應的方法以成功完成,可以提交事務.
  4. 事務可以回滾的關鍵關鍵在於IUnitOfWork物件在被dispose時候會檢查complete方法有沒有被執行,沒有的話就認為這個UOW標註的方法沒有順利完成,從而導致事務的回滾操作。
  5. 整個事務的提交是通過第一個UOW(也是唯一個)complete方法執行時提交的。

InnerUnitOfWorkCompleteHandle關於檢查complete方法有沒有被執行的程式碼

UnitOfWorkManagerbeign方法。這邊可以看出只有一個IUnitOfWork物件會被建立, 而且由於這個物件是通過容器直接resolve的,那麼ABP怎麼知道該通過resolve得到什麼樣的例項呢?是EfUnitOfWork?還是MongoDbUnitOfWork?還是MemoryDbUnitOfWork?還是NhUnitOfWork?答案是ABP不知道,ABP作者假設你只會用其中一個模組,所以如果你把這四個module都加入到你的專案中,結果是不可預知的。

EfUnitOfWork在begin方法中建立.NET事務

EfUnitOfWork提交事務

CallContextCurrentUnitOfWorkProvider

CallContextCurrentUnitOfWorkProvider的主要功能其實只有一個:通過current返回當前UOW環境下的UOW例項。

一般思路是:將IUnitOfWork物件定義為例項變數或者是類變數。 但是兩者事實上都不可行。

如果定義為類變數,那就會面臨執行緒安全的問題,解決方式無非加鎖,但會導致併發能力下降,ABPweb框架,因為鎖導致併發能力下降是不能接受的。

如果定義為例項變數,在同一執行緒其他地方resolve CallContextCurrentUnitOfWorkProvider這個例項的時候都會得到一個新的例項,新的例項下current自然是NULL.

ABP的做法是:執行緒邏輯上下文+執行緒安全的Dictinoray容器

執行緒邏輯上下文用於儲存UOW例項的key, 而執行緒邏輯上下文對於本執行緒是全域性可訪問的,而同時具有天然的隔離性。這就確保了當前執行緒的各個地方都可以得到currentUOWkey

執行緒安全的Dictinoray容器是一個類例項,用於存放UOW的例項,通過UOWkey就可以取到UOW的例項。

相關推薦

ABP原始碼分析Unit Of Work

ABP以AOP的方式實現UnitOfWork功能。通過UnitOfWorkRegistrar將UnitOfWorkInterceptor在某個類被註冊到IOCContainner的時候,一併新增到該類在容器中對應的ComponentModel的Interceptors集合中。總結一句話就是,UOW的功能是通過

ABP原始碼分析Entity的設計

IEntity<TPrimaryKey>: 封裝了PrimaryKey:Id,這是一個泛型型別 IEntity: 封裝了PrimaryKey:Id,這是一個int型別 Entity<TPrimaryKey> :支援主鍵是泛型型別的Entity Entity:支援主鍵是int型別的

ABP原始碼分析DTO的設計

IDTO:空介面,用於標註Dto物件。 ComboboxItemDto:用於combobox/list中Item的DTO NameValueDto<T>/NameValueDto:用於name value鍵值對的DTO, name為string型別, value為泛型或string型別。

ABP原始碼分析DTO 自動校驗的實現

對傳給Application service物件中的方法的DTO引數,ABP都會在方法真正執行前自動完成validation(根據標註到DTO物件中的validate規則)。 ABP是如何做到的? 思路無外乎通過Castle的攔截器實現AOP。本文主要分析ABP是如何設計。 Ivalidate: 空介面,用

ABP原始碼分析本地化

本文逐個分析ABP中涉及到locaization的介面和類,以及相互之間的關係。本地化主要涉及兩個方面:一個是語言(Language)的管理,這部分相對簡單。另一個是語言對應得本地化資源(Localization)的管理,這部分稍顯複雜。 LanguageInfo:用於封裝language的基本

ABP原始碼分析Auditing

審計跟蹤(也叫審計日誌)是與安全相關的按照時間順序的記錄,它們提供了活動序列的文件證據,這些活動序列可以在任何時間影響一個特定的操作。 AuditInfo:定義如下圖中需要被Audit的資訊。 AuditedAttribute: 用於標識一個方法或一個類的所有方法都需要啟用Auditing功能

ABP原始碼分析Timing

Timing這個簡單實用的功能主要用於以統一的方式表示時間。因為ABP中有大量的module,還支援自定義module,所以將時間統一表示為local時間(預設)或utc時間是必要的。 IClockProvider:提供獲取當前時間和標準化時間的介面。 UtcClockProvider:實現了以UTC

ABP原始碼分析UI Inputs

以下圖中描述的介面和類都在Abp專案的Runtime/Validation, UI/Inputs目錄下的。在當前版本的ABP(0.83)中這些介面和類並沒有實際使用到。閱讀程式碼時可以忽略,無需浪費時間去尋找其是如何被ABP使用的(本文的目的)。 這些介面和類最終都是通過IInputType被Feature

[Abp 原始碼分析]四、DTO 自動驗證

0.簡介 在平時開發 API 介面的時候需要對前端傳入的引數進行校驗之後才能進入業務邏輯進行處理,否則一旦前端傳入一些非法/無效資料到 API 當中,輕則導致程式報錯,重則導致整個業務流程出現問題。 用過傳統 ASP.NET MVC 資料註解的同學應該知道,我們可以通過在 Model 上面指定各種資料特性,然

[Abp 原始碼分析]五、自動審計記錄

0.簡介 Abp 框架為我們自帶了審計日誌功能,審計日誌可以方便地檢視每次請求介面所耗的時間,能夠幫助我們快速定位到某些效能有問題的介面。除此之外,審計日誌資訊還包含有每次呼叫介面時客戶端請求的引數資訊,客戶端的 IP 與客戶端使用的瀏覽器。有了這些資料之後,我們就可以很方便地復現介面產生 BUG 時的一些環

[Abp 原始碼分析]六、後臺作業與後臺工作者

0. 簡介 在某些時候我們可能會需要執行後臺任務,或者是執行一些週期性的任務。比如說可能每隔 1 個小時要清除某個臨時資料夾內的資料,可能使用者會要針對某一個使用者群來群發一組簡訊。前面這些就是典型的應用場景,在 Abp 框架裡面為我們準備了後臺作業和後臺工作者來幫助我們解決這個問題。 後臺作業與後臺工作者的

[Abp 原始碼分析]七、ASP.NET Core 整合

0. 簡介 整個 Abp 框架最為核心的除了 Abp 庫之外,其次就是 Abp.AspNetCore 庫了。雖然 Abp 本身是可以用於控制檯程式的,不過那樣的話 Abp 就基本沒什麼用,還是需要集合 ASP.NET Core 才能發揮它真正的作用。 在 Abp.AspNetCore 庫裡面,Abp 通過 W

[Abp 原始碼分析]一、許可權驗證

0.簡介 Abp 本身集成了一套許可權驗證體系,通過 ASP.NET Core 的過濾器與 Castle 的攔截器進行攔截請求,並進行許可權驗證。在 Abp 框架內部,許可權分為兩塊,一個是功能(Feature),一個是許可權項(Permission),在更多的時候兩者僅僅是概念不同而已,大體處理流程還是一樣

[Abp 原始碼分析]、異常處理

0.簡介 Abp 框架本身針對內部丟擲異常進行了統一攔截,並且針對不同的異常也會採取不同的處理策略。在 Abp 當中主要提供了以下幾種異常型別: 異常型別 描述 AbpException Abp 框架定義的基本異常型別,Abp 所有內部定義的異常型別都繼承自本類。 AbpInitializa

ABP原始碼分析ABP Module

Abp是一種基於模組化設計的思想構建的。開發人員可以將自定義的功能以模組(module)的形式整合到ABP中。具體的功能都可以設計成一個單獨的Module。Abp底層框架提供便捷的方法整合每個Module.下圖是所有Abp自帶的module.AbpModule是所有Module的基類,其已經擁有了IIocMa

ABP原始碼分析整體專案結構及目錄

ABP是一套非常優秀的web應用程式架構,適合用來搭建集中式架構的web應用程式。 整個Abp的Infrastructure是以Abp這個package為核心模組(core)+15個模組(module).其中13個依賴於Abp這個核心包。另外兩個包(FluentMigration,Web.Resources

ABP原始碼分析ABP初始化全過程

ABP在初始化階段做了哪些操作,前面的四篇文章大致描述了一下。 為個更清楚的描述其脈絡,做了張流程圖以輔助說明。其中每一步都涉及很多細節,難以在一張圖中全部表現出來。每一步的細節(會涉及到較多介面,類,呼叫關係,步驟流程什麼的)會在後面的文章中通過其他圖和文字詳細描述。其實如果仔細分析Abp原始碼的話,會發現

ABP原始碼分析十三快取Cache實現

ABP中有兩種cache的實現方式:MemroyCache 和 RedisCache. 如下圖,兩者都繼承至ICache介面(準確說是CacheBase抽象類)。ABP核心模組封裝了MemroyCache 來實現ABP中的預設快取功能。 Abp.RedisCache這個模組封裝RedisCache來實現快取(

ABP原始碼分析Logger整合

ABP使用Castle日誌記錄工具,並且可以使用不同的日誌類庫,比如:Log4Net, NLog, Serilog... 等等。對於所有的日誌類庫,Castle提供了一個通用的介面來實現,我們可以很方便的處理各種特殊的日誌庫,而且當業務需要的時候,很容易替換日誌元件。 Logger功能模組涉及到的介面和類不

ABP原始碼分析Configuration

核心模組的配置 Configuration是ABP中設計比較巧妙的地方。其通過AbpStartupConfiguration,Castle的依賴注入,Dictionary物件和擴充套件方法很巧妙的實現了配置中心化。配置中心化是一個支援模組開發的框架必備功能。 ABP中核心功能模組中的一些功能的執行時的