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源码分析系列文章目录

ABP源码分析十:Unit Of Work的更多相关文章

  1. C# DateTime的11种构造函数 [Abp 源码分析]十五、自动审计记录 .Net 登陆的时候添加验证码 使用Topshelf开发Windows服务、记录日志 日常杂记——C#验证码 c#_生成图片式验证码 C# 利用SharpZipLib生成压缩包 Sql2012如何将远程服务器数据库及表、表结构、表数据导入本地数据库

    C# DateTime的11种构造函数   别的也不多说没直接贴代码 using System; using System.Collections.Generic; using System.Glob ...

  2. ABP源码分析十二:本地化

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

  3. ABP源码分析十四:Entity的设计

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

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

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

  5. ABP源码分析十六:DTO的设计

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

  6. ABP源码分析十八:UI Inputs

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

  7. ABP源码分析十九:Auditing

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

  8. [Abp 源码分析]十二、多租户体系与权限验证

    0.简介 承接上篇文章我们会在这篇文章详细解说一下 Abp 是如何结合 IPermissionChecker 与 IFeatureChecker 来实现一个完整的多租户系统的权限校验的. 1.多租户的 ...

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

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

随机推荐

  1. Angular2入门系列教程5-路由(一)-使用简单的路由并在在路由中传递参数

    上一篇:Angular2入门系列教程-服务 上一篇文章我们将Angular2的数据服务分离出来,学习了Angular2的依赖注入,这篇文章我们将要学习Angualr2的路由 为了编写样式方便,我们这篇 ...

  2. CSS Position 定位属性

    本篇文章主要介绍元素的Position属性,此属性可以设置元素在页面的定位方式. 目录 1. 介绍 position:介绍position的值以及辅助属性. 2. position 定位方式:介绍po ...

  3. PHP之GD函数的使用

    本文讲解常用GD函数的应用 1.一个简单的图像 我们先看一个例子: <?php $w = 200; $h = 200; $img = imagecreatetruecolor($w,$h); $ ...

  4. C# await和async

    基础阅读:http://www.cnblogs.com/jesse2013/p/async-and-await.html 答疑阅读:http://www.cnblogs.com/heyuquan/ar ...

  5. 如何优化coding

    如何优化coding 前言 最近一直在做修改bug工作,修改bug花费时间最多的不是如何解决问题而是怎样快速读懂代码.如果代码写的好的,不用debug就可以一眼看出来哪里出了问题.实际上,我都要deb ...

  6. Effective java笔记(二),所有对象的通用方法

    Object类的所有非final方法(equals.hashCode.toString.clone.finalize)都要遵守通用约定(general contract),否则其它依赖于这些约定的类( ...

  7. JAVA 设计模式之策略模式

    定义:定义一组算法,将每个算法都封装起来,并且使他们之间可以互换. 类型:行为类模式 策略模式是对算法的封装,把一系列的算法分别封装到对应的类中,并且这些类实现相同的接口,相互之间可以替换.在前面说过 ...

  8. 在Linux虚拟机下配置jdk的环境变量

    1.到Oracle公司的官网里下载好jdk,网址 http://www.oracle.com/technetwork/java/javase/downloads/jdk8-downloads-2133 ...

  9. [斜率优化DP]【学习笔记】【更新中】

    参考资料: 1.元旦集训的课件已经很好了 http://files.cnblogs.com/files/candy99/dp.pdf 2.http://www.cnblogs.com/MashiroS ...

  10. ASP.NET Aries JSAPI 文档说明:AR.Form、AR.Combobox

    AR.Form 文档 1:对象或属性: 名称 类型 说明 data 属性 编辑页根据主键请求回来的数据 method 属性 用于获取数据的函数指向,默认值Get objName 属性 用于拦截form ...