Abp Uow 设计
分类:
IT文章
•
2023-11-23 10:35:13
初始化入口
在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的博文,推荐看一下
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
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 }
/// <summary>
/// Should be implemented by derived classes to complete UOW.
/// </summary>
protected abstract void CompleteUow();
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 }
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 }
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 }
1 protected override void CompleteUow()
2 {
3 SaveChanges(); //遍历EfContent,调用SaveChange方法
4 if (CurrentTransaction != null) //如果存在事务则执行
5 {
6 CurrentTransaction.Complete();
7 }
8 }