初始化入口

在AbpKernelModule类中,通过UnitOfWorkRegistrar.Initialize(IocManager) 方法去初始化

 /// <summary>
/// This class is used to register interceptor for needed classes for Unit Of Work mechanism.
/// </summary>
internal static class UnitOfWorkRegistrar
{
/// <summary>
/// Initializes the registerer.
/// </summary>
/// <param name="iocManager">IOC manager</param>
public static void Initialize(IIocManager iocManager)
{
iocManager.IocContainer.Kernel.ComponentRegistered += ComponentRegistered;
} private static void ComponentRegistered(string key, IHandler handler)
{
if (UnitOfWorkHelper.IsConventionalUowClass(handler.ComponentModel.Implementation))
{
//Intercept all methods of all repositories.
handler.ComponentModel.Interceptors.Add(new InterceptorReference(typeof(UnitOfWorkInterceptor)));
}
else if (handler.ComponentModel.Implementation.GetMethods(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic).Any(UnitOfWorkHelper.HasUnitOfWorkAttribute))
{
//Intercept all methods of classes those have at least one method that has UnitOfWork attribute.
//TODO: Intecept only UnitOfWork methods, not other methods!
handler.ComponentModel.Interceptors.Add(new InterceptorReference(typeof(UnitOfWorkInterceptor)));
}
}
}

UnitOfWorkRegistrar

UnitOfWorkInterceptor 拦截器

基于Castle.Core的AOP动态拦截

区分同步异步,通过UowManager开启事务

 private void PerformUow(IInvocation invocation, UnitOfWorkOptions options)
{
if (AsyncHelper.IsAsyncMethod(invocation.Method))
{
PerformAsyncUow(invocation, options);
}
else
{
PerformSyncUow(invocation, options);
}
} private void PerformSyncUow(IInvocation invocation, UnitOfWorkOptions options)
{
using (var uow = _unitOfWorkManager.Begin(options))
{
invocation.Proceed();
uow.Complete();
}
}

PerformUow

invocation.Proceed();会嵌套执行,将Uow嵌套包含,嵌套的Uow不会单独再开启事务,通过InnerUnitOfWorkCompleteHandle标识,全部完成后complete,提交事务(UnitOfWorkDefaultOptions默认开启事务)

UnitOfWorkManager

UnitOfWorkManager 继承IUnitOfWorkManager

 /// <summary>
/// Unit of work manager.
/// Used to begin and control a unit of work.
/// </summary>
public interface IUnitOfWorkManager
{
/// <summary>
/// Gets currently active unit of work (or null if not exists).
/// </summary>
IActiveUnitOfWork Current { get; } /// <summary>
/// Begins a new unit of work.
/// </summary>
/// <returns>A handle to be able to complete the unit of work</returns>
IUnitOfWorkCompleteHandle Begin(); /// <summary>
/// Begins a new unit of work.
/// </summary>
/// <returns>A handle to be able to complete the unit of work</returns>
IUnitOfWorkCompleteHandle Begin(TransactionScopeOption scope); /// <summary>
/// Begins a new unit of work.
/// </summary>
/// <returns>A handle to be able to complete the unit of work</returns>
IUnitOfWorkCompleteHandle Begin(UnitOfWorkOptions options);
}

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的博文,推荐看一下

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的操作是在EfUnitOfWorkNhUnitOfWork这样的之类中实现的)。UOW中除了事务控制逻辑以外的逻辑都是由UnitOfWorkBase抽象类实现的。

     /// <summary>
/// Defines a unit of work.
/// This interface is internally used by ABP.
/// Use <see cref="IUnitOfWorkManager.Begin()"/> to start a new unit of work.
/// </summary>
public interface IUnitOfWork : IActiveUnitOfWork, IUnitOfWorkCompleteHandle
{
/// <summary>
/// Unique id of this UOW.
/// </summary>
string Id { get; } /// <summary>
/// Reference to the outer UOW if exists.
/// </summary>
IUnitOfWork Outer { get; set; } /// <summary>
/// Begins the unit of work with given options.
/// </summary>
/// <param name="options">Unit of work options</param>
void Begin(UnitOfWorkOptions options);
}

IUnitOfWork

UnitOfWorkBase中的Begin实现如下:

 public void Begin(UnitOfWorkOptions options)
{
if (options == null)
{
throw new ArgumentNullException("options");
} PreventMultipleBegin();      //通过_isBeginCalledBefore 字段bool判断是否已经begin
Options = options; //TODO: Do not set options like that, instead make a copy? SetFilters(options.FilterOverrides);    //通过设置过滤器达到全局数据过滤的效果,在ef的实现中,通过引用EntityFramework.DynamicFilter实现 BeginUow();
}

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方法。

         /// <inheritdoc/>
public void Complete()
{
PreventMultipleComplete();    //通过_isCompleteCalledBefore字段Bool判断是否已经Complete,保证只执行一次
try
{
CompleteUow();
_succeed = true;
OnCompleted();        //调用完成的事件,在UnitOfWorkManager中设置,当前的UnitOfWork为null
}
catch (Exception ex)
{
_exception = ex;
throw;
}
}

4.Dispose

         /// <inheritdoc/>
public void Dispose()
{
if (IsDisposed)
{
return;
} IsDisposed = true; if (!_succeed)          //在Complete是会设置_succeed,没有成功则执行Faild事件,会将当前的UnitOfWord设为null
{
OnFailed(_exception);
} DisposeUow();          //为抽象方法,在子类中实现
OnDisposed();          //OnFailed和OnDisposed均在UnitOfWordManage中设置
}

EfUnitOfWork

1.BeginUow

         protected override void BeginUow()
{
if (Options.IsTransactional == true)
{
var transactionOptions = new TransactionOptions
{
IsolationLevel = Options.IsolationLevel.GetValueOrDefault(IsolationLevel.ReadUncommitted),
}; if (Options.Timeout.HasValue)
{
transactionOptions.Timeout = Options.Timeout.Value;
} CurrentTransaction = new TransactionScope(                      //开启事务,并给定默认为Required
Options.Scope.GetValueOrDefault(TransactionScopeOption.Required),
transactionOptions,
Options.AsyncFlowOption.GetValueOrDefault(TransactionScopeAsyncFlowOption.Enabled)
);
}
}

2.CompleteUow

         protected override void CompleteUow()
{
SaveChanges();              //遍历EfContent,调用SaveChange方法
if (CurrentTransaction != null)    //如果存在事务则执行
{
CurrentTransaction.Complete();
}
}

Abp Uow 设计的更多相关文章

  1. ABP架构设计交流群-上海线下交流会的内容分享(有高清录像视频的链接)

    点这里进入ABP系列文章总目录 ABP架构设计交流群-7月18日上海线下交流会内容分享 因为最近工作特别忙,很久没有更新博客了,真对不起关注我博客和ABP系列文章的朋友! 原计划在7月11日举行的AB ...

  2. ABP模块设计

    ABP模块设计 返回ABP系列 ABP是“ASP.NET Boilerplate Project (ASP.NET样板项目)”的简称. ASP.NET Boilerplate是一个用最佳实践和流行技术 ...

  3. ABP分层设计

    ABP分层设计 一.为什么要分层 分层架构是所有架构的鼻祖,分层的作用就是隔离,不过,我们有时候有个误解,就是把层和程序集对应起来,就比如简单三层架构中,在你的解决方案中,一般会有三个程序集项目:XX ...

  4. 基于DDD的.NET开发框架 - ABP分层设计

    返回ABP系列 ABP是“ASP.NET Boilerplate Project (ASP.NET样板项目)”的简称. ASP.NET Boilerplate是一个用最佳实践和流行技术开发现代WEB应 ...

  5. 持续提升程序员幸福指数——使用abp vnext设计一款面向微服务的单体架构

    可能你会面临这样一种情况,在架构设计之前,你对业务不甚了解,需求给到的也模棱两可,这个时候你既无法明确到底是要使用单体架构还是使用微服务架构,如果使用单体,后续业务扩展可能带来大量修改,如果使用微服务 ...

  6. 基于DDD的.NET开发框架 - ABP模块设计

    返回ABP系列 ABP是“ASP.NET Boilerplate Project (ASP.NET样板项目)”的简称. ASP.NET Boilerplate是一个用最佳实践和流行技术开发现代WEB应 ...

  7. ABP 初探 之 权限设计

    大.小项目都要设计权限,都想设计一个通用的权限,把权限做的比较复杂,现在了解了ABP的设计思路,觉得设计很简单,但实现方法与思路耐人寻味. 本篇只介绍AbpPermissions的数据库设计,其它表结 ...

  8. ABP 初探 之User、Role、Permission数据库设计 (EntityFramework 继承的另一种使用方法)

    最近群里(134710707)的朋友都在讨论ABP源码,我把最近学习的内容记录下来,同时也分享给大家,希望正在研究ABP源码的朋友有一定帮助. 上篇介绍ABP的多语言,本篇主要介绍权限的数据库设计,用 ...

  9. User、Role、Permission数据库设计ABP

    ABP 初探 之User.Role.Permission数据库设计 (EntityFramework 继承的另一种使用方法) 最近群里(134710707)的朋友都在讨论ABP源码,我把最近学习的内容 ...

随机推荐

  1. OpenCV3+Python3

    OpenCV3计算机视觉Python语言实现笔记 图像处理与OpenCV Python3与OpenCV3.3 图像处理 OpenCV文摘 基于Python3 + OpenCV3.3.1的远程监控程序 ...

  2. JS自定义去除字符串左右两边的指定字符

    function ltrim(str,char){ var pos = str.indexOf(char); var sonstr = str.substr(pos+1); return sonstr ...

  3. Python @ddt.file_data() 为.yml 文件实例

    一,创建login.yml 文件(以登录接口为例) 1,创建 login.yml 文件,内容如下图: 打印login.yml 文件,代码及显示效果如下: 代码: import yaml,jsonf = ...

  4. web.py+fastcgi+nginx 502错误解决

    用web.py照着官网在服务器上搭好了后台.这次很奇怪地出现了一个Nginx 502 Bad Gateway的错误. 执行上面的kill `pgrep -f "python /path/to ...

  5. 如​何​使​用​P​H​P​开​发​高​效​的​W​E​B​系​统

    PHP是一个非常优秀的工具,它能够简单,也能够复杂.不一样的项目,应该用不一样的PHP.  小项目 - 简单而直接的PHP 一般对于一个功能页面在20下面的站点.我们能够用一个非常easy的框架结构来 ...

  6. resize2fs命令出现这个错误“resize2fs: Operation not permitted While trying to add group #6656” 有数据的会丢数据

    1. resize2fs命令出现这个错误“resize2fs: Operation not permitted While trying to add group #6656”,并且在/var/log ...

  7. jQuery中ajax的使用与缓存问题的解决方法

    http://www.jb51.net/article/44620.htm —————————————————————————————————————————————————————————————— ...

  8. Hibernate Annotation 字段 默认值

    http://emavaj.blog.163.com/blog/static/133280557201032262741999/ ——————————————————————————————————— ...

  9. 精心收集的Hadoop学习资料(持续更新)

    转自:http://blog.csdn.net/wypblog/article/details/17528851 最近发现自己收集到的Hadoop学习资料有很多本,想想放在那里也浪费,所以觉得贴出来给 ...

  10. 《linux系统及其编程》实验课记录(四)

    实验4:组织目录和文件 实验目标: 熟悉几个基本的操作系统文件和目录的命令的功能.语法和用法, 整理出一个更有条理的主目录,每个文件都位于恰当的子目录. 实验背景: 你的主目录中已经积压了一些文件,你 ...