Abp Uow 设计
初始化入口
在AbpKernelModule类中,通过UnitOfWorkRegistrar.Initialize(IocManager) 方法去初始化
1 /// <summary> 2 /// This class is used to register interceptor for needed classes for Unit Of Work mechanism. 3 /// </summary> 4 internal static class UnitOfWorkRegistrar 5 { 6 /// <summary> 7 /// Initializes the registerer. 8 /// </summary> 9 /// <param name="iocManager">IOC manager</param> 10 public static void Initialize(IIocManager iocManager) 11 { 12 iocManager.IocContainer.Kernel.ComponentRegistered += ComponentRegistered; 13 } 14 15 private static void ComponentRegistered(string key, IHandler handler) 16 { 17 if (UnitOfWorkHelper.IsConventionalUowClass(handler.ComponentModel.Implementation)) 18 { 19 //Intercept all methods of all repositories. 20 handler.ComponentModel.Interceptors.Add(new InterceptorReference(typeof(UnitOfWorkInterceptor))); 21 } 22 else if (handler.ComponentModel.Implementation.GetMethods(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic).Any(UnitOfWorkHelper.HasUnitOfWorkAttribute)) 23 { 24 //Intercept all methods of classes those have at least one method that has UnitOfWork attribute. 25 //TODO: Intecept only UnitOfWork methods, not other methods! 26 handler.ComponentModel.Interceptors.Add(new InterceptorReference(typeof(UnitOfWorkInterceptor))); 27 } 28 } 29 }
UnitOfWorkRegistrar
UnitOfWorkInterceptor 拦截器
基于Castle.Core的AOP动态拦截
区分同步异步,通过UowManager开启事务
1 private void PerformUow(IInvocation invocation, UnitOfWorkOptions options) 2 { 3 if (AsyncHelper.IsAsyncMethod(invocation.Method)) 4 { 5 PerformAsyncUow(invocation, options); 6 } 7 else 8 { 9 PerformSyncUow(invocation, options); 10 } 11 } 12 13 private void PerformSyncUow(IInvocation invocation, UnitOfWorkOptions options) 14 { 15 using (var uow = _unitOfWorkManager.Begin(options)) 16 { 17 invocation.Proceed(); 18 uow.Complete(); 19 } 20 }
PerformUow
invocation.Proceed();会嵌套执行,将Uow嵌套包含,嵌套的Uow不会单独再开启事务,通过InnerUnitOfWorkCompleteHandle标识,全部完成后complete,提交事务(UnitOfWorkDefaultOptions默认开启事务)
UnitOfWorkManager
UnitOfWorkManager 继承IUnitOfWorkManager
1 /// <summary> 2 /// Unit of work manager. 3 /// Used to begin and control a unit of work. 4 /// </summary> 5 public interface IUnitOfWorkManager 6 { 7 /// <summary> 8 /// Gets currently active unit of work (or null if not exists). 9 /// </summary> 10 IActiveUnitOfWork Current { get; } 11 12 /// <summary> 13 /// Begins a new unit of work. 14 /// </summary> 15 /// <returns>A handle to be able to complete the unit of work</returns> 16 IUnitOfWorkCompleteHandle Begin(); 17 18 /// <summary> 19 /// Begins a new unit of work. 20 /// </summary> 21 /// <returns>A handle to be able to complete the unit of work</returns> 22 IUnitOfWorkCompleteHandle Begin(TransactionScopeOption scope); 23 24 /// <summary> 25 /// Begins a new unit of work. 26 /// </summary> 27 /// <returns>A handle to be able to complete the unit of work</returns> 28 IUnitOfWorkCompleteHandle Begin(UnitOfWorkOptions options); 29 }
IUnitOfWorkManager
在Begin方法中根据option的设置,创建了一个新的Uow,并设置了Uow相应的Completed,Failed,Disposed的方法。
CallContextCurrentUnitOfWorkProvider
这里有必要提一下CallContextCurrentUnitOfWorkProvider 的对象,他继承ICurrentUnitOfWorkProvider
CallContextCurrentUnitOfWorkProvider的主要功能其实只有一个:通过current返回当前UOW环境下的UOW实例。
一般思路是:将IUnitOfWork对象定义为实例变量或者是类变量。 但是两者事实上都不可行。
如果定义为类变量,那就会面临线程安全的问题,解决方式无非加锁,但会导致并发能力下降,ABP是web框架,因为锁导致并发能力下降是不能接受的。
如果定义为实例变量,在同一线程其他地方resolve CallContextCurrentUnitOfWorkProvider这个实例的时候都会得到一个新的实例,新的实例下current自然是NULL.
ABP的做法是:线程逻辑上下文+线程安全的Dictinoray容器。
线程逻辑上下文用于存储UOW实例的key, 而线程逻辑上下文对于本线程是全局可访问的,而同时具有天然的隔离性。这就确保了当前线程的各个地方都可以得到current的UOW的key
线程安全的Dictinoray容器是一个类实例,用于存放UOW的实例,通过UOW的key就可以取到UOW的实例。(引用: http://www.cnblogs.com/1zhk/p/5309043.html)
这里有两篇CallContext的博文,推荐看一下
如何实现对上下文(Context)数据的统一管理 [提供源代码下载]
CallContext和多线程
UnitOfWork
1.UnitOfWorkBase
接下来,分析下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抽象类实现的。
1 /// <summary> 2 /// Defines a unit of work. 3 /// This interface is internally used by ABP. 4 /// Use <see cref="IUnitOfWorkManager.Begin()"/> to start a new unit of work. 5 /// </summary> 6 public interface IUnitOfWork : IActiveUnitOfWork, IUnitOfWorkCompleteHandle 7 { 8 /// <summary> 9 /// Unique id of this UOW. 10 /// </summary> 11 string Id { get; } 12 13 /// <summary> 14 /// Reference to the outer UOW if exists. 15 /// </summary> 16 IUnitOfWork Outer { get; set; } 17 18 /// <summary> 19 /// Begins the unit of work with given options. 20 /// </summary> 21 /// <param name="options">Unit of work options</param> 22 void Begin(UnitOfWorkOptions options); 23 }
IUnitOfWork
UnitOfWorkBase中的Begin实现如下:
1 public void Begin(UnitOfWorkOptions options) 2 { 3 if (options == null) 4 { 5 throw new ArgumentNullException("options"); 6 } 7 8 PreventMultipleBegin(); //通过_isBeginCalledBefore 字段bool判断是否已经begin 9 Options = options; //TODO: Do not set options like that, instead make a copy? 10 11 SetFilters(options.FilterOverrides); //通过设置过滤器达到全局数据过滤的效果,在ef的实现中,通过引用EntityFramework.DynamicFilter实现 12 13 BeginUow(); 14 }
2.开始UnitOfWork
CompleteUow和BeginUow 在UowBase中为抽象方法,具体实现在efUow中,稍后分析
/// <summary>/// Should be implemented by derived classes to complete UOW./// </summary>protected abstract void CompleteUow();
3.Complete
Complete方法在UnitOfWorkInterceptor拦截中,PerformSyncUow方法内,执行完invocation.Proceed();会调用Complete方法。
1 /// <inheritdoc/> 2 public void Complete() 3 { 4 PreventMultipleComplete(); //通过_isCompleteCalledBefore字段Bool判断是否已经Complete,保证只执行一次 5 try 6 { 7 CompleteUow(); 8 _succeed = true; 9 OnCompleted(); //调用完成的事件,在UnitOfWorkManager中设置,当前的UnitOfWork为null 10 } 11 catch (Exception ex) 12 { 13 _exception = ex; 14 throw; 15 } 16 }
4.Dispose
1 /// <inheritdoc/> 2 public void Dispose() 3 { 4 if (IsDisposed) 5 { 6 return; 7 } 8 9 IsDisposed = true; 10 11 if (!_succeed) //在Complete是会设置_succeed,没有成功则执行Faild事件,会将当前的UnitOfWord设为null 12 { 13 OnFailed(_exception); 14 } 15 16 DisposeUow(); //为抽象方法,在子类中实现 17 OnDisposed(); //OnFailed和OnDisposed均在UnitOfWordManage中设置 18 }
EfUnitOfWork
1.BeginUow
1 protected override void BeginUow() 2 { 3 if (Options.IsTransactional == true) 4 { 5 var transactionOptions = new TransactionOptions 6 { 7 IsolationLevel = Options.IsolationLevel.GetValueOrDefault(IsolationLevel.ReadUncommitted), 8 }; 9 10 if (Options.Timeout.HasValue) 11 { 12 transactionOptions.Timeout = Options.Timeout.Value; 13 } 14 15 CurrentTransaction = new TransactionScope( //开启事务,并给定默认为Required 16 Options.Scope.GetValueOrDefault(TransactionScopeOption.Required), 17 transactionOptions, 18 Options.AsyncFlowOption.GetValueOrDefault(TransactionScopeAsyncFlowOption.Enabled) 19 ); 20 } 21 }
2.CompleteUow
1 protected override void CompleteUow() 2 { 3 SaveChanges(); //遍历EfContent,调用SaveChange方法 4 if (CurrentTransaction != null) //如果存在事务则执行 5 { 6 CurrentTransaction.Complete(); 7 } 8 }
转载于:https://www.cnblogs.com/Hai--D/p/5482009.html
Abp Uow 设计相关推荐
- 基于DDD的.NET开发框架 - ABP模块设计
返回ABP系列 ABP是"ASP.NET Boilerplate Project (ASP.NET样板项目)"的简称. ASP.NET Boilerplate是一个用最佳实践和流行 ...
- UnitOfWork以及其在ABP中的应用
Unit Of Work(UoW)模式在企业应用架构中被广泛使用,它能够将Domain Model中对象状态的变化收集起来,并在适当的时候在同一数据库连接和事务处理上下文中一次性将对象的变更提交到数据 ...
- [Abp vNext 源码分析] - 4. 工作单元
一.简要说明 统一工作单元是一个比较重要的基础设施组件,它负责管理整个业务流程当中涉及到的数据库事务,一旦某个环节出现异常自动进行回滚处理. 在 ABP vNext 框架当中,工作单元被独立出来作为一 ...
- 基于DDD的现代ASP.NET开发框架--ABP系列之1、ABP总体介绍
点这里进入ABP系列文章总目录 基于DDD的现代ASP.NET开发框架--ABP系列之1.ABP总体介绍 ABP是"ASP.NET Boilerplate Project (ASP.NET样 ...
- ABP理论学习之授权(Authorization)
返回总目录 本篇目录 介绍 定义权限 检查权限 使用AbpAuthorize特性 使用IPermissionChecker Razor视图 客户端(Javascript) 权限管理者 介绍 几乎所有的 ...
- ABP理论学习之仓储
本篇目录 IRepository接口 查询 插入 更新 删除 其他 关于异步方法 仓储实现 管理数据库连接 仓储的生命周期 仓储最佳实践 Martin Fowler对仓储的定义 位于领域层和数据映射层 ...
- ABP(现代ASP.NET样板开发框架)系列之2、ABP入门教程
点这里进入ABP系列文章总目录 基于DDD的现代ASP.NET开发框架--ABP系列之2.ABP入门教程 ABP是"ASP.NET Boilerplate Project (ASP.NET样 ...
- Asp.Net Core 工作单元 UnitOfWork UOW
Asp.Net Core 工作单元示例 来自 ABP UOW 去除所有无用特性 代码下载 : 去除所有无用特性版本,原生AspNetCore实现 差不多 2278 行代码: 链接:https://pa ...
- Abp vNext异常处理的缺陷/改造方案
之前吐槽Abp的用户/租户管理模块!今天我又来了,这次我给Abp官方repo提了一个issue. 目前Website使用Abp vNext开发,免不了要全局处理异常.提示服务器异常信息. 1. Abp ...
最新文章
- Tip#66:你知道吗?如何在输入属性值时自动插入双引号
- ES6中Generator理解
- Python标准库01 正则表达式(re包)
- 经典算法笔记:异常检测和推荐系统
- 说实话,你的API接口在高并发面前不堪一击!
- iOS开发事件分发机制—响应链—手势影响
- 2012年12月第二个周末
- 无法使用JDK 8卸载JavaFX SceneBuilder 1.0
- vue引用electron_如何搞定跨平台桌面开发?Electron助你快速起步
- 欢迎来到Python循环小课堂
- LeetCode 166. 分数到小数
- 译文丨伯克利对serverless的看法:简化云编程
- 【代码保留】IP地址排序(字符串分隔补齐)
- 百度地图城市代码CityID
- matlab 组装刚度矩阵,求整体刚度矩阵matlab程序
- 人这一辈子,渡你的只有两个人
- 心理月刊杂志心理月刊杂志社心理月刊编辑部2022年第11期目录
- C语言实现设置桌面壁纸
- GOF23设计模式之桥接模式
- 程序员们,千万不要接私活
热门文章
- 【Uva - 10047 】The Monocycle(搜索,bfs记录状态)
- java redis 重连_突破Java面试(23-4) - Redis 复制原理
- ubuntu cpp与mysql连接_linux(ubuntu)下C++访问mysql数据库
- 简单 局部 整体光照模型计算机图形学,计算机图形学北大光照模型.ppt
- c语言判断这天是星期几,【求指导!!】输入年,月,日,然后判断这天是星期几!!!!!...
- matlab cd参数,MATLAB变量参数列表​
- java屏蔽编译告警_java-禁止JAXB生成的类上的编译器警告
- Eclipse中使用Checkstyle,checkstyle插件检查java代码的自定义配置文件:
- C++:31---对象引用和赋值
- Redis:08---字符串对象