ABP以AOP的方式实现UnitOfWork功能。通过UnitOfWorkRegistrar将UnitOfWorkInterceptor在某个类被注册到IOCContainner的时候,一并添加到该类在容器中对应的ComponentModel的Interceptors集合中。总结一句话就是,UOW的功能是通过自定义Castle拦截器来实现的。本文主要介绍ABP核心框架中的UnitOfWork的实现,后续会分别介绍ABP其他模块是如何具体实现IUnitOfWork的

如图,AbpKernelModule调用UnitOfWorkRegister的Initialize方法将UnitOfWorkInterceptor拦截器添加到标注了UnitOfWork特性方法的类,以及实现IRepository或IApplicationService的类上。

下图是UnitOfWorkRegister的代码

和通常实现的AOP一样,ABP定义了UnitOfWork特性,方便业务层为方法注入UOW功能。

UnitOfWorkAttribute:用于标注某个方法位UnitOfWork的Attribute类. 通过这个特性,可以指定是否启用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的操作是在EfUnitOfWork,NhUnitOfWork这样的之类中实现的)。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方法有没有被执行的代码

UnitOfWorkManager的beign方法。这边可以看出只有一个IUnitOfWork对象会被创建, 而且由于这个对象是通过容器直接resolve的,那么ABP怎么知道该通过resolve得到什么样的实例呢?是EfUnitOfWork?还是MongoDbUnitOfWork?还是MemoryDbUnitOfWork?还是NhUnitOfWork?答案是ABP不知道,ABP作者假设你只会用其中一个模块,所以如果你把这四个module都加入到你的项目中,结果是不可预知的。

EfUnitOfWork在begin方法中创建.NET事务

EfUnitOfWork提交事务

CallContextCurrentUnitOfWorkProvider

CallContextCurrentUnitOfWorkProvider的主要功能其实只有一个:通过current返回当前UOW环境下的UOW实例。

一般思路是:将IUnitOfWork对象定义为实例变量或者是类变量。 但是两者事实上都不可行。

如果定义为类变量,那就会面临线程安全的问题,解决方式无非加锁,但会导致并发能力下降,ABP是web框架,因为锁导致并发能力下降是不能接受的。

如果定义为实例变量,在同一线程其他地方resolve CallContextCurrentUnitOfWorkProvider这个实例的时候都会得到一个新的实例,新的实例下current自然是NULL.

ABP的做法是:线程逻辑上下文+线程安全的Dictinoray容器。

线程逻辑上下文用于存储UOW实例的key, 而线程逻辑上下文对于本线程是全局可访问的,而同时具有天然的隔离性。这就确保了当前线程的各个地方都可以得到current的UOW的key

线程安全的Dictinoray容器是一个类实例,用于存放UOW的实例,通过UOW的key就可以取到UOW的实例。

返回ABP源码分析系列文章目录

Q:我有个问题想请教。关于ABP的事务机制。
1.为什么事务要切入所有继承IRepository和IApplicationService的类,这样的话所有的继承类方法都AOP了,虽然实际的事务只有在访问dbcontext的时候UOW才会被初始化,但单查询的方法,ABP也要开启一次事务,是不是非常低效啊。
2.如果我在Appcliation对象中手写事务想缩短事务执行时间,它会不会被ABP的事务机制影响。

A:如果仅仅是读数据,那么可以在方法上加上特性[UnitOfWork(isTransactional: false)]以关闭事务。

Q:这种方式感觉不是很好。
我仔细看了下代码,ABP默认事务的隔离级别是IsolationLevel=ReadUncommitted,作者的意图是不是要给读操作加个nolock而这么实现的啊。因为EF加nolock都是要起事务的。

A:IsolationLevel=ReadUncommitted 不等于给读操作加个nolock。 ABP是通过TransactionScope来控制事务的。没有对EF操作做特殊处理。

A:作者分析的不错,但是ABP得工作单元也是可以实现EF和MongoDb的这种切换的。

A:引用作者分析的不错,但是ABP得工作单元也是可以实现EF和MongoDb的这种切换的。

Q:今天在一个方法中有EF和MongoDb结果一直报错。。。 Unable to cast object of type 'Abp.EntityFrameworkCore.Uow.EfCoreUnitOfWork' to type 'Abp.MongoDb.Uow.MongoDbUnitOfWork'.

Q:应该是UnitOfWorkRegistrar而不是UnitOfWorkRegister

【转】ABP源码分析十:Unit Of Work相关推荐

  1. 【转】ABP源码分析十九:Auditing

    审计跟踪(也叫审计日志)是与安全相关的按照时间顺序的记录,它们提供了活动序列的文档证据,这些活动序列可以在任何时间影响一个特定的操作. AuditInfo:定义如下图中需要被Audit的信息. Aud ...

  2. 【转】ABP源码分析十八:UI Inputs

    以下图中描述的接口和类都在Abp项目的Runtime/Validation, UI/Inputs目录下的.在当前版本的ABP(0.83)中这些接口和类并没有实际使用到.阅读代码时可以忽略,无需浪费时间 ...

  3. 【转】ABP源码分析十六:DTO的设计

    IDTO:空接口,用于标注Dto对象. ComboboxItemDto:用于combobox/list中Item的DTO NameValueDto<T>/NameValueDto:用于na ...

  4. 【转】ABP源码分析十五:ABP中的实用扩展方法

    类名 扩展的类型 方法名 参数 作用 XmlNodeExtensions XmlNode GetAttributeValueOrNull attributeName Gets an   attribu ...

  5. 【转】ABP源码分析十四:Entity的设计

    IEntity<TPrimaryKey>: 封装了PrimaryKey:Id,这是一个泛型类型 IEntity: 封装了PrimaryKey:Id,这是一个int类型 Entity< ...

  6. 【转】ABP源码分析十二:本地化

    本文逐个分析ABP中涉及到localization的接口和类,以及他们之间的关系.本地化主要涉及两个方面:一个是语言(Language)的管理,这部分相对简单.另一个是语言对应得本地化资源(Local ...

  7. [Abp 源码分析]十六、后台作业与后台工作者

    0. 简介 在某些时候我们可能会需要执行后台任务,或者是执行一些周期性的任务.比如说可能每隔 1 个小时要清除某个临时文件夹内的数据,可能用户会要针对某一个用户群来群发一组短信.前面这些就是典型的应用 ...

  8. 【转】ABP源码分析二十九:ABP.MongoDb

    这个Module通过建立一个MongoDbRepositoryBase<TEntity> 基类,封装了对MongoDb数据库的操作. 这个module通过引用MongoDB.Driver, ...

  9. 【转】ABP源码分析一:整体项目结构及目录

    ABP是一套非常优秀的web应用程序架构,适合用来搭建集中式架构的web应用程序. 整个Abp的Infrastructure是以Abp这个package为核心模块(core)+15个模块(module ...

最新文章

  1. /scripts/checkkconfigsymbols.sh
  2. INTERSPEECH 2017系列 | 语音识别之语言模型技术
  3. FFmpeg转HTML5支持的视频格式
  4. 运维工程师是桥的护栏_桥梁专家:钢结构桥比混凝土桥易涡振 以后出现涡振可能性会提高...
  5. @Test 运行 Method xxx should be void、Method xxx should have no parameters
  6. 遗传算法编码方式整数编码_如何编码卫星算法并从头开始烹制西班牙海鲜饭
  7. string中获取所有数字
  8. python回到首行_python读取文件首行和最后一行
  9. Flex移动性能检查列表
  10. timestamp和recycle同时开启,导致连接成功率降低
  11. C# 子类实例化基类 基类使用不了子类的方法_C#中的类、方法和属性
  12. Visual C++ 2011-5-18
  13. 企业数字化转型需注意什么
  14. Linux中如何针对用户及组设置磁盘配额
  15. linux c Make file 的生成
  16. 折腾黑苹果的正确潜入姿势(系统版本:macOS Catalina 10.15)
  17. 英伟达(NVIDIA)系列显卡(GPU)技术指标对比排行
  18. 华为Routing Switching切换为Datacom,究竟变了些什么
  19. average函数例子c语言数组,average函数(average函数使用例子)
  20. Django新手入门教程(2)测试服务器是否可用

热门文章

  1. EF(Entity FrameWork)实体框架
  2. Python之模块与包(下)
  3. JavaScript原生对象及扩展
  4. Longest Substring With At Most K Distinct Characters
  5. ImageView及其子类
  6. 151. Reverse Words in a String
  7. 818. Race Car
  8. 【数据结构与算法】广度优先遍历(BFS) 深度优先遍历(DFS)
  9. [Leetcode][第96题][JAVA][不同的二叉搜索树][动态规划][数学]
  10. java非堆内存_java – 监视JVM的非堆内存使用情况