ABP源码分析十:Unit Of Work
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大致运行流程如下
- UOW拦截器被注入到需要UOW的类中。
- ABP执行标注了UnitOfWork特性的方法时。UOW拦截器以begin()->realAction()->complete()->dispose()顺序执行,其中realAction是被调用的真实业务操作。 UOW拦截器是通过using这种方式调用IUnitOfWork的某个具体实现,这就确保begin 和 dispose也总是会被执行的。 这里需要注意complete却不一定会被执行,比如在complete方法被调用前方法的执行产生了异常。
- 当执行一连串的操作时(A方法->B方法->C方法,假设这三个方法都标注了UnitOfWork特性),ABP在执行A方法前会创建整个过程中唯一的IUnitOfWork对象,该对象会启动.NET事务。在执行到B,C方法只会创建InnerUnitOfWorkCompleteHandle。 InnerUnitOfWorkCompleteHandle与IUnitOfWork对象的差异在于它不会创建真实的事务。但ABP会调用其complete,以告知ABP其对应的方法以成功完成,可以提交事务.
- 事务可以回滚的关键关键在于IUnitOfWork对象在被dispose时候会检查complete方法有没有被执行,没有的话就认为这个UOW标注的方法没有顺利完成,从而导致事务的回滚操作。
- 整个事务的提交是通过第一个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源码分析十:Unit Of Work的更多相关文章
- C# DateTime的11种构造函数 [Abp 源码分析]十五、自动审计记录 .Net 登陆的时候添加验证码 使用Topshelf开发Windows服务、记录日志 日常杂记——C#验证码 c#_生成图片式验证码 C# 利用SharpZipLib生成压缩包 Sql2012如何将远程服务器数据库及表、表结构、表数据导入本地数据库
C# DateTime的11种构造函数 别的也不多说没直接贴代码 using System; using System.Collections.Generic; using System.Glob ...
- ABP源码分析十二:本地化
本文逐个分析ABP中涉及到locaization的接口和类,以及相互之间的关系.本地化主要涉及两个方面:一个是语言(Language)的管理,这部分相对简单.另一个是语言对应得本地化资源(Locali ...
- ABP源码分析十四:Entity的设计
IEntity<TPrimaryKey>: 封装了PrimaryKey:Id,这是一个泛型类型 IEntity: 封装了PrimaryKey:Id,这是一个int类型 Entity< ...
- ABP源码分析十五:ABP中的实用扩展方法
类名 扩展的类型 方法名 参数 作用 XmlNodeExtensions XmlNode GetAttributeValueOrNull attributeName Gets an attribu ...
- ABP源码分析十六:DTO的设计
IDTO:空接口,用于标注Dto对象. ComboboxItemDto:用于combobox/list中Item的DTO NameValueDto<T>/NameValueDto:用于na ...
- ABP源码分析十八:UI Inputs
以下图中描述的接口和类都在Abp项目的Runtime/Validation, UI/Inputs目录下的.在当前版本的ABP(0.83)中这些接口和类并没有实际使用到.阅读代码时可以忽略,无需浪费时间 ...
- ABP源码分析十九:Auditing
审计跟踪(也叫审计日志)是与安全相关的按照时间顺序的记录,它们提供了活动序列的文档证据,这些活动序列可以在任何时间影响一个特定的操作. AuditInfo:定义如下图中需要被Audit的信息. Aud ...
- [Abp 源码分析]十二、多租户体系与权限验证
0.简介 承接上篇文章我们会在这篇文章详细解说一下 Abp 是如何结合 IPermissionChecker 与 IFeatureChecker 来实现一个完整的多租户系统的权限校验的. 1.多租户的 ...
- [Abp 源码分析]十六、后台作业与后台工作者
0. 简介 在某些时候我们可能会需要执行后台任务,或者是执行一些周期性的任务.比如说可能每隔 1 个小时要清除某个临时文件夹内的数据,可能用户会要针对某一个用户群来群发一组短信.前面这些就是典型的应用 ...
随机推荐
- 浅谈我对DDD领域驱动设计的理解
从遇到问题开始 当人们要做一个软件系统时,一般总是因为遇到了什么问题,然后希望通过一个软件系统来解决. 比如,我是一家企业,然后我觉得我现在线下销售自己的产品还不够,我希望能够在线上也能销售自己的产品 ...
- AngularJs之九(ending......)
今天继续angularJs,但也是最后一篇关于它的了,基础部分差不多也就这些,后续有机会再写它的提升部分. 今天要写的也是一个基础的选择列表: 一:使用ng-options,数组进行循环. <d ...
- 构建通用的 React 和 Node 应用
这是一篇非常优秀的 React 教程,这篇文章对 React 组件.React Router 以及 Node 做了很好的梳理.我是 9 月份读的该文章,当时跟着教程做了一遍,收获很大.但是由于时间原因 ...
- [C#] C# 知识回顾 - 学会处理异常
学会处理异常 你可以使用 try 块来对你觉得可能会出现异常的代码进行分区. 其中,与之关联的 catch 块可用于处理任何异常情况. 一个包含代码的 finally 块,无论 try 块中是否在运行 ...
- 非关系型数据库(NoSql)
最近了解了一点非关系型数据库,刚刚接触,觉得这是一个很好的方向,对于大数据 方面的处理,非关系型数据库能起到至关重要的地位.这里我主要是整理了一些前辈的经验,仅供参考. 关系型数据库的特点 1.关系型 ...
- javascript 判断参数类型大全
js 判断类型的在开发中是很常用的,因为js 是弱类型的语言,var 可以接受任何形式的类型,但是在真正的开发中,我们需要根据不同类型做不同的处理,所以这个是必须的精通. 首先需要知道 typeof这 ...
- 关于.NET参数传递方式的思考
年关将近,整个人已经没有了工作和写作的激情,估计这个时候很多人跟我差不多,该相亲的相亲,该聚会喝酒的聚会喝酒,总之就是没有了干活的心思(我有很多想法,但就是叫不动我的手脚,所以我只能看着别人在做我想做 ...
- Asp.net Core准备工作
1.安装环境 安装.Net Core SDK 安装VS2015 Update3 安装DotNetCore.1.0.1-VS2015Tools.Preview2.0.2.exe 2.新建Core工程 项 ...
- Response.Redirect引起的性能问题分析
现象: 最近做的一个系统通过单点登录(SSO) 技术验证用户登录.用户在SSO 系统上通过验证后,跳转到该系统的不同模块.而跳转的时间一直维持子啊几分钟左右. 分析步骤: 在问题复现时抓取Hang d ...
- 极光推送和友盟推送,ios端和安卓端的后端调试设置
我是最后端的,这两天搞了一个app项目,前端安卓使用友盟很方便,调试比较顺利,然后ios就遇到各种问题了,证书.发送成功推送不成功,测试时用的TestMode(),ios上架之后就必须用product ...