【转】ABP源码分析十:Unit Of Work
ABP以AOP的方式實(shí)現(xiàn)UnitOfWork功能。通過UnitOfWorkRegistrar將UnitOfWorkInterceptor在某個(gè)類被注冊(cè)到IOCContainner的時(shí)候,一并添加到該類在容器中對(duì)應(yīng)的ComponentModel的Interceptors集合中。總結(jié)一句話就是,UOW的功能是通過自定義Castle攔截器來實(shí)現(xiàn)的。本文主要介紹ABP核心框架中的UnitOfWork的實(shí)現(xiàn),后續(xù)會(huì)分別介紹ABP其他模塊是如何具體實(shí)現(xiàn)IUnitOfWork的
?
如圖,AbpKernelModule調(diào)用UnitOfWorkRegister的Initialize方法將UnitOfWorkInterceptor攔截器添加到標(biāo)注了UnitOfWork特性方法的類,以及實(shí)現(xiàn)IRepository或IApplicationService的類上。
?
下圖是UnitOfWorkRegister的代碼
?
和通常實(shí)現(xiàn)的AOP一樣,ABP定義了UnitOfWork特性,方便業(yè)務(wù)層為方法注入U(xiǎn)OW功能。
UnitOfWorkAttribute:用于標(biāo)注某個(gè)方法位UnitOfWork的Attribute類.?通過這個(gè)特性,可以指定是否啟用UOW,事務(wù)隔離級(jí)別,TransactionScopeOption等
UnitOfWorkOptions:?封裝了UnitOfWork參數(shù)的類,其實(shí)例是通過UnitOfWorkAttribute的CreateOptions來生成的。
?
?
接下來,分析下UnitOfWork是如何封裝事務(wù)的。
基于接口隔離原則的考量,ABP作者將UnitOfWork的方法分到了三個(gè)不同的接口中,如下圖。
IUnitOfWorkCompleteHandle:定義了UOW同步和異步的complete方法。實(shí)現(xiàn)UOW完成時(shí)候的邏輯。
?
IActiveUnitOfWork:一個(gè)UOW除了以上兩個(gè)接口中定義的方法和屬性外,其他的屬性和方法都在這個(gè)接口定義的。比如Completed,Disposed,Failed事件代理,Filter的enable和disable,以及同步、異步的SaveChanges方法。
?
IUnitOfWork:繼承了上面兩個(gè)接口。定義了外層的IUnitOfWork的引用和UOW的begin方法。 ABP是通過構(gòu)建一個(gè)UnitOfWork的鏈,將不同的方法納入到一個(gè)事務(wù)中(后文解釋)。
UnitOfWorkBase:這個(gè)抽象類實(shí)現(xiàn)了上面三個(gè)接口中定義的方法,而真正實(shí)現(xiàn)事務(wù)控制的方法是由這個(gè)抽象類的子類實(shí)現(xiàn)的(比如,真正創(chuàng)建TransactionScope的操作是在EfUnitOfWork,NhUnitOfWork這樣的之類中實(shí)現(xiàn)的)。UOW中除了事務(wù)控制邏輯以外的邏輯都是由UnitOfWorkBase抽象類實(shí)現(xiàn)的。
?
?
ABP中共有以下4個(gè)具體的UOW類型,他們都繼承自UnitOfWorkBase。Entity Framework, Nhibernate UnitOfWork是實(shí)現(xiàn)事務(wù)控制的UOW。MongoDB?和?MemoryDB UnitOfWork是沒有事務(wù)控制的。 原因很簡(jiǎn)單,MongoDB本身就沒有完整的事務(wù)控制功能, 而ABP 框架實(shí)現(xiàn)的MemoryDB也是沒有事務(wù)控制功能的。
?
IUnitOfWorkManager/UnitOfWorkManager:和其他***manager類一樣是一個(gè)Facade,他對(duì)外提供UOW的功能(用于創(chuàng)建UnitOfWork,并開啟UnitOfWork流程),對(duì)內(nèi)調(diào)用各種UOW功能的各種組件。
?
UnitOfWork攔截器調(diào)用UnitOfWorkManager開啟UOW流程的代碼。
?
Unit Of Work大致運(yùn)行流程如下
?
?
InnerUnitOfWorkCompleteHandle關(guān)于檢查complete方法有沒有被執(zhí)行的代碼
?
UnitOfWorkManager的beign方法。這邊可以看出只有一個(gè)IUnitOfWork對(duì)象會(huì)被創(chuàng)建,?而且由于這個(gè)對(duì)象是通過容器直接resolve的,那么ABP怎么知道該通過resolve得到什么樣的實(shí)例呢?是EfUnitOfWork?還是MongoDbUnitOfWork?還是MemoryDbUnitOfWork?還是NhUnitOfWork?答案是ABP不知道,ABP作者假設(shè)你只會(huì)用其中一個(gè)模塊,所以如果你把這四個(gè)module都加入到你的項(xiàng)目中,結(jié)果是不可預(yù)知的。
?
EfUnitOfWork在begin方法中創(chuàng)建.NET事務(wù)
?
EfUnitOfWork提交事務(wù)
?
?
?
?
CallContextCurrentUnitOfWorkProvider
CallContextCurrentUnitOfWorkProvider的主要功能其實(shí)只有一個(gè):通過current返回當(dāng)前UOW環(huán)境下的UOW實(shí)例。
一般思路是:將IUnitOfWork對(duì)象定義為實(shí)例變量或者是類變量。?但是兩者事實(shí)上都不可行。
如果定義為類變量,那就會(huì)面臨線程安全的問題,解決方式無非加鎖,但會(huì)導(dǎo)致并發(fā)能力下降,ABP是web框架,因?yàn)殒i導(dǎo)致并發(fā)能力下降是不能接受的。
如果定義為實(shí)例變量,在同一線程其他地方resolve?CallContextCurrentUnitOfWorkProvider這個(gè)實(shí)例的時(shí)候都會(huì)得到一個(gè)新的實(shí)例,新的實(shí)例下current自然是NULL.
ABP的做法是:線程邏輯上下文+線程安全的Dictinoray容器。
線程邏輯上下文用于存儲(chǔ)UOW實(shí)例的key,?而線程邏輯上下文對(duì)于本線程是全局可訪問的,而同時(shí)具有天然的隔離性。這就確保了當(dāng)前線程的各個(gè)地方都可以得到current的UOW的key
線程安全的Dictinoray容器是一個(gè)類實(shí)例,用于存放UOW的實(shí)例,通過UOW的key就可以取到UOW的實(shí)例。
?
?
返回ABP源碼分析系列文章目錄
?
Q:我有個(gè)問題想請(qǐng)教。關(guān)于ABP的事務(wù)機(jī)制。
1.為什么事務(wù)要切入所有繼承IRepository和IApplicationService的類,這樣的話所有的繼承類方法都AOP了,雖然實(shí)際的事務(wù)只有在訪問dbcontext的時(shí)候UOW才會(huì)被初始化,但單查詢的方法,ABP也要開啟一次事務(wù),是不是非常低效啊。
2.如果我在Appcliation對(duì)象中手寫事務(wù)想縮短事務(wù)執(zhí)行時(shí)間,它會(huì)不會(huì)被ABP的事務(wù)機(jī)制影響。
A:如果僅僅是讀數(shù)據(jù),那么可以在方法上加上特性[UnitOfWork(isTransactional: false)]以關(guān)閉事務(wù)。
?
Q:這種方式感覺不是很好。
我仔細(xì)看了下代碼,ABP默認(rèn)事務(wù)的隔離級(jí)別是IsolationLevel=ReadUncommitted,作者的意圖是不是要給讀操作加個(gè)nolock而這么實(shí)現(xiàn)的啊。因?yàn)镋F加nolock都是要起事務(wù)的。
?
A:IsolationLevel=ReadUncommitted 不等于給讀操作加個(gè)nolock。 ABP是通過TransactionScope來控制事務(wù)的。沒有對(duì)EF操作做特殊處理。
?
A:作者分析的不錯(cuò),但是ABP得工作單元也是可以實(shí)現(xiàn)EF和MongoDb的這種切換的。
?
A:引用作者分析的不錯(cuò),但是ABP得工作單元也是可以實(shí)現(xiàn)EF和MongoDb的這種切換的。
Q:今天在一個(gè)方法中有EF和MongoDb結(jié)果一直報(bào)錯(cuò)。。。 Unable to cast object of type 'Abp.EntityFrameworkCore.Uow.EfCoreUnitOfWork' to type 'Abp.MongoDb.Uow.MongoDbUnitOfWork'.
??
Q:應(yīng)該是UnitOfWorkRegistrar而不是UnitOfWorkRegister
總結(jié)
以上是生活随笔為你收集整理的【转】ABP源码分析十:Unit Of Work的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 地球的历史很黑暗:我们每个人都是幸存者、
- 下一篇: 发布三个月:Intel Arc显卡终于支