初始化入口

在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. 12. Min Stack【medium】

    Implement a stack with min() function, which will return the smallest number in the stack. It should ...

  2. 如何利用dex2jar反编译APK

    工具/原料 电脑 dex2jar JD-GUI 方法/步骤 1 下载dex2jar和JD-GUI,在参考资料中添加了这两个工具的百度网盘下载地址供读者下载使用(笔者亲测) 2 找到我们准备测试用的ap ...

  3. Java 之进制转换

    //十进制转十六进制 import java.util.Scanner; public class Main{ public static void main(String[] args){ Scan ...

  4. Jquery 事件执行两次

    js(jquery)的on绑定点击事件执行两次的解决办法—不是事件绑定而是事件冒泡 阻止冒泡的方法并不止 return false 这一种,还有event.stopPropagation(),这两种方 ...

  5. 跟着百度学PHP[12]-文件处理 文件 目录

    00x1 文件的属性 文件属性 <?php //-------------------------定义大小转换函数--------------- function changesize_dw($ ...

  6. UNION types numeric and text cannot be matched

    NULL ::NUMERIC 有时候会遇到这个问题,那是因为几个SQL组合在一起的时候,同一个字段的值,出来了不同类型的时候,这种时候就需要进行转型的处理了.

  7. jQuery插件开发全解析<转>

    jQuery插件的开发包括两种: 一种是类级别的插件开发,即给jQuery添加新的全局函数,相当于给jQuery类本身添加方法.jQuery的全局函数就是属于jQuery命名空间的函数,另一种是对象级 ...

  8. C语言错误: CRT detected that the application wrote to memory after end of heap buffer

    CRT detected that the application wrote to memory after end of heap buffer 多是中间对其进行了一些操作,在程序结束处,释放内存 ...

  9. python中的列表生成式

    列表生成式即List Comprehensions,是Python内置的非常简单却强大的可以用来创建list的生成式. 举个例子,要生成list [1, 2, 3, 4, 5, 6, 7, 8, 9, ...

  10. 007杰信-factory的启用+停用

    业务需求:当有一些factory与我们不在合作时,我们不能直接删除这个公司的数据,我们采用的办法是在factory_c表增加一个字段STATE(CHAR(1)),1表示是启用,0是表示停用. 准备工作 ...