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的操作是在EfUnitOfWorkNhUnitOfWork这样的之类中实现的)。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

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/457943.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

python3.8 实现鼠标自动移动_“新生报到”!【移动机器人 HD-1500】负载1500kg,实现了重型货物运输的自动化...

2020年第三季度欧姆龙自动化&#xff08;中国&#xff09;有限公司新品【移动机器人 HD-1500】即日起在中国市场首次对外发布&#xff0c;实现了重型货物运输的自动化。这款最新的自动化移动机器人重型载荷能力为1500 kg&#xff01;更高的载荷能力可以令客户实现以前无法实现的…

android 监听本机网络请求_fiddler如何抓取https请求实现fiddler手机抓包-证书安装失败100%解决...

一、HTTP协议和HTTPS协议。(1) HTTPS协议HTTP协议SSL协议&#xff0c;默认端口&#xff1a;443(2) HTTP协议&#xff08;HyperText Transfer Protocol&#xff09;&#xff1a;超文本传输协议。默认端口&#xff1a;80&#xff0c;其中包含请求和响应两部分&#xff0c;其中请求…

C#的四舍五入函数

2019独角兽企业重金招聘Python工程师标准>>> 1.四舍六入&#xff08;国外的四舍五入&#xff09; Math.Round&#xff08;num&#xff09;; 2.四舍五入 Math.Round(num,MidpointRounding.AwayFromZero); 转载于:https://my.oschina.net/CrazyBoy1024/blog/746268

【BZOJ2243】 [SDOI2011]染色

Description 给定一棵有n个节点的无根树和m个操作&#xff0c;操作有2类&#xff1a; 1、将节点a到节点b路径上所有点都染成颜色c&#xff1b; 2、询问节点a到节点b路径上的颜色段数量&#xff08;连续相同颜色被认为是同一段&#xff09;&#xff0c;如“112221”由3段组成&am…

数字信号处理的fpga实现_FPGA数字信号处理:通信类I/Q信号及产生

大侠好&#xff0c;欢迎来到FPGA技术江湖&#xff0c;江湖偌大&#xff0c;相见即是缘分。大侠可以关注FPGA技术江湖&#xff0c;在“闯荡江湖”、"行侠仗义"栏里获取其他感兴趣的资源&#xff0c;或者一起煮酒言欢。大侠好&#xff0c;“宁夏李治廷”再一次和各位见…

iic通讯协议

IIC总线 一般串行数据通讯都有时钟和数据之分,有异步和同步之别. 有单线,双线和三线等. I2C肯定是2线的(不算地线). I2C协议确实很科学,比3/4线的SPI要好,当然线多通讯速率相对就快了. I2C的原则是: 在SCL1(高电平)时,SDA千万别忽悠!!! 否则,SDA下跳则"判罚"为&…

使用 Python 切割图片

刚好我有张 PNG 图片需要均匀切割&#xff0c;刚好我不会 PhotoShop&#xff0c;刚好我想用 Python 来练练手。 于是撸袖子码脚本。 import os from PIL import Imagedef splitimage(src, rownum, colnum, dstpath):img Image.open(src)w, h img.sizeif rownum < h and co…

python数据分析知识点_Python数据分析--Pandas知识点(三)

本文主要是总结学习pandas过程中用到的函数和方法, 在此记录, 防止遗忘. 下面将是在知识点一, 二的基础上继续总结. 前面所介绍的都是以表格的形式中展现数据, 下面将介绍Pandas与Matplotlib配合绘制出折线图, 散点图, 饼图, 柱形图, 直方图等五大基本图形. Matplotlib是python…

SPI通讯协议

SPI&#xff1a;高速同步串行口。是一种标准的四线同步双向串行总线。 SPI&#xff0c;是英语Serial Peripheral interface的缩写&#xff0c;顾名思义就是串行外围设备接口。是Motorola首先在其MC68HCXX系列处理器上定义的。SPI接口主要应用在 EEPROM&#xff0c;FLASH&#x…

基于MVVM的知乎日报应用安卓源码

使用data binding , dagger2 , retrofit2和rxjava实现的&#xff0c;基于MVVM的知乎日报APP运行效果&#xff1a; <ignore_js_op> 使用说明&#xff1a; 项目结构android data binding来实现MVVM。dagger2来完成依赖注入。retrofit2rxjava实现restful的http请求。第三方类…

php签入html出来的影响seo吗_搜索引擎优化_SEO必备6大技能+SEO误区讲解!

大家好&#xff0c;我是逆冬&#xff0c;今天来分享一下实战SEO需要掌握什么样的技能以及SEO知识误区&#xff0c;本篇文章仅代表逆冬本人几年的经验、不见得适合每一个SEOer!下面就让逆冬本人来分析一下实战型SEO到底需要掌握什么技能。第1点&#xff1a;SEO需要不需要熟练掌握…

一种M2M业务的架构及实现M2M业务的方法

http://www.cnblogs.com/coryxie/p/3849764.html 技术领域 [0001] 本发明涉及通信技术领域&#xff0c;尤其涉及一种M2M业务的架构及实现M2M业务的方法。 背景技术 [0002] 随着通信技术的飞速发展以及通信技术与互联网技术的进一步融合&#xff0c;移动业务以及移动互联网技术普…

第二章 mybatis使用注解实现in查询(mysql)

mybatis实现in查询&#xff0c;两种方法&#xff1a; xml形式&#xff08;推荐&#xff09;注解方式&#xff08;个人喜欢注解&#xff0c;但是in场景可能不太适合注解&#xff09;代码&#xff1a; 1 Select("<script>" 2 "SELECT ID…

python面试代码题_python面试基础篇80题

1.为什么学习python?3.Python和Java、PHP、C、C#、C等其他语言的对比&#xff1f; C语言由于其底层操作特性和历史的积累&#xff0c;在嵌入式领域是当之无愧的王者。 PHP跨平台&#xff0c;性能优越&#xff0c;跟linux/unix结合比跟windows结合性能强45%,开发成本低,php5已经…

javascript 变量作用域

为什么80%的码农都做不了架构师&#xff1f;>>> javascript中的变量的作用域不同于java/c的变量规则。 1、在java/c中&#xff0c;如果有一个全局变量与一个局部变量重名&#xff0c;那么在局部变量的作用域中&#xff0c;局部变量会覆盖掉全局变量的值。当离开局部…

七月算法--12月机器学习在线班-第五次课笔记—回归

七月算法--12月机器学习在线班-第五次课笔记—回归 七月算法&#xff08;julyedu.com&#xff09;12月机器学习在线班学习笔记 http://www.julyedu.com 转载于:https://www.cnblogs.com/sweet-dew/p/5491271.html

公司网络搭建及×××到公司配置

一、公司路由器及子网配置公司192.168.1.0/24子网用于服务器集群&#xff0c;192.168.0.0/24子网用于办公子网&#xff0c;两个子网物理上不在一块。公司开业时&#xff0c;申请了电信40Mbps专线光纤&#xff0c;5个IP地址&#xff0c;网关&#xff1a;*.168.112.9 255.255.25…

蓝鸥零基础学习HTML5第五讲 CSS的基础样式

蓝鸥零基础学习HTML5第五讲 CSS的基础样式1.border<!DOCTYPE html><html lang"en"><head><meta charset"UTF-8"><title>Document</title><style>div {width:0px;height:0px;/*background: url("img/1.jpg…

C# 使用Conditional特性而不是#if条件编译

概述 #if/#endif 语句常用来基于同一份源码生成不同的编译结果&#xff0c;其中最常见的就是debug版和release版。但是这些工具在实际应用中并不是非常友好&#xff0c;因为它们容易被滥用&#xff0c;其代码页进而难以理解或调试。C#设计中考虑到这个问题&#xff0c;并提供了…

python安装opencv出现错误_Python3安装OpenCV出错,如何解决?

$ sudo pip install opencv-python $ sudo pip install opencv-contrib-python 参考下&#xff1a;python作业毕设&#xff1a;安装人工智能图像处理工具OpenCV​zhuanlan.zhihu.compython版本安装 适合所有平台&#xff1a; $ sudo pip install opencv-python $ sudo pip inst…