ABP中UnitOfWorkRegistrar拦截器是整个ABP中非常关键的一个部分,这个部分在整个业务系统中也是用的最多的一个部分,这篇文章的主要思路并不是写如何使用ABP中的UnitOfWork,重点在于分析整个ABP框架中是如何实现工作单元的,如果想了解如何快速使用ABP中的UnitOfWork,请读下面的文章,这个是ABP的官方文档。

  整个过程的分析还是按照之前系列拦截器中的顺序进行说明,首先是从AbpBootstrapper中的构造函数开始说起。

/// <summary>
/// Creates a new <see cref="AbpBootstrapper"/> instance.
/// </summary>
/// <param name="startupModule">Startup module of the application which depends on other used modules. Should be derived from <see cref="AbpModule"/>.</param>
/// <param name="optionsAction">An action to set options</param>
private AbpBootstrapper([NotNull] Type startupModule, [CanBeNull] Action<AbpBootstrapperOptions> optionsAction = null)
{
Check.NotNull(startupModule, nameof(startupModule)); var options = new AbpBootstrapperOptions();
optionsAction?.Invoke(options); if (!typeof(AbpModule).GetTypeInfo().IsAssignableFrom(startupModule))
{
throw new ArgumentException($"{nameof(startupModule)} should be derived from {nameof(AbpModule)}.");
} StartupModule = startupModule; IocManager = options.IocManager;
PlugInSources = options.PlugInSources; _logger = NullLogger.Instance; if (!options.DisableAllInterceptors)
{
AddInterceptorRegistrars();
}
}

  如果我们没有在初始化的时候配置DisableAllInterceptors=true的情况下,默认是开启所有的拦截器的,然后在AddInterceptorRegistrars()方法中会执行UnitOfWorkRegistrar.Initialize(IocManager)方法,从而开始了整个UnitOfWorkRegistrar的初始化操作,那么让我们一起进入到UnitOfWorkRegistrar这个静态类中去分析整个过程吧!  

/// <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 += (key, handler) =>
{
var implementationType = handler.ComponentModel.Implementation.GetTypeInfo(); HandleTypesWithUnitOfWorkAttribute(implementationType, handler);
HandleConventionalUnitOfWorkTypes(iocManager, implementationType, handler);
};
} private static void HandleTypesWithUnitOfWorkAttribute(TypeInfo implementationType, IHandler handler)
{
if (IsUnitOfWorkType(implementationType) || AnyMethodHasUnitOfWork(implementationType))
{
handler.ComponentModel.Interceptors.Add(new InterceptorReference(typeof(UnitOfWorkInterceptor)));
}
} private static void HandleConventionalUnitOfWorkTypes(IIocManager iocManager, TypeInfo implementationType, IHandler handler)
{
if (!iocManager.IsRegistered<IUnitOfWorkDefaultOptions>())
{
return;
} var uowOptions = iocManager.Resolve<IUnitOfWorkDefaultOptions>(); if (uowOptions.IsConventionalUowClass(implementationType.AsType()))
{
handler.ComponentModel.Interceptors.Add(new InterceptorReference(typeof(UnitOfWorkInterceptor)));
}
} private static bool IsUnitOfWorkType(TypeInfo implementationType)
{
return UnitOfWorkHelper.HasUnitOfWorkAttribute(implementationType);
} private static bool AnyMethodHasUnitOfWork(TypeInfo implementationType)
{
return implementationType
.GetMethods(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic)
.Any(UnitOfWorkHelper.HasUnitOfWorkAttribute);
}
}

  就像这个类最开始的说明一样,这个类的作用是为了用于需要Unit Of Work机制的类注册拦截器的,在这个类的Initialize方法中,首先会注入整个ABP系统中唯一的IIocManager,然后就是订阅唯一的IocContainer这个容器的ComponentRegistered事件,在订阅事件中首先是获取当前触发此事件的类型信息,接下来就是执行HandleTypesWithUnitOfWorkAttribute这个方法,这个方法中主要是判断当前方法是否定义了UnitOfWork这个自定义属性,如果当前方法定义了这个自定义UnitOfWork属性的话,那么就注册UnitOfWorkInterceptor这个拦截器,后面一个HandleConventionalUnitOfWorkTypes这个方法我们可以看看里面的一些关键过程,这里面核心的是调用了Abp.Domain.Uow命名空间下面的静态类UnitOfWorkDefaultOptionsExtensions中的IsConventionalUowClass方法,在这个方法中又会去调用UnitOfWorkDefaultOptions : IUnitOfWorkDefaultOptions这个类中的 public List<Func<Type, bool>> ConventionalUowSelectors { get; }这个委托List,从而确定当前类型是否需要注入UnitOfWorkInterceptor这个拦截器,执行到这里最关键的就是ConventionalUowSelectors 这个委托的List到底默认添加了哪些类型的委托?我们来看看这个类的初始化过程。  

 public UnitOfWorkDefaultOptions()
{
_filters = new List<DataFilterConfiguration>();
IsTransactional = true;
Scope = TransactionScopeOption.Required; IsTransactionScopeAvailable = true; ConventionalUowSelectors = new List<Func<Type, bool>>
{
type => typeof(IRepository).IsAssignableFrom(type) ||
typeof(IApplicationService).IsAssignableFrom(type)
};
}

  看完了这个你应该明白了,ABP中会默认为继承自IRepository或者是IApplicationService的两种类型添加UnitOfWork特性,看完了这个你肯定在想如果自己也需要添加自定义的规则那该怎么办?这里ABP中强大的Configuration就起大作用了,这里只需要在继承自AbpModule类的PreInitialize方法中加入下面的代码就可以了。  

Configuration.UnitOfWork.ConventionalUowSelectors.Add(type => ...);

  至此所有支持UnitOfWork特性的类型及方法我们就都理解了,至少我们知道ABP中默认为哪些方法或类型添加UnitOfWork特性已经自己如何自定义一些规则使我们的代码能够使用这个特性。

  后面一个部分就是深入理解UnitOfWorkInterceptor这个拦截器了,还是和前面一样,我们来看看这个类中到底写了些什么?

/// <summary>
/// This interceptor is used to manage database connection and transactions.
/// </summary>
internal class UnitOfWorkInterceptor : IInterceptor
{
private readonly IUnitOfWorkManager _unitOfWorkManager;
private readonly IUnitOfWorkDefaultOptions _unitOfWorkOptions; public UnitOfWorkInterceptor(IUnitOfWorkManager unitOfWorkManager, IUnitOfWorkDefaultOptions unitOfWorkOptions)
{
_unitOfWorkManager = unitOfWorkManager;
_unitOfWorkOptions = unitOfWorkOptions;
} /// <summary>
/// Intercepts a method.
/// </summary>
/// <param name="invocation">Method invocation arguments</param>
public void Intercept(IInvocation invocation)
{
MethodInfo method;
try
{
method = invocation.MethodInvocationTarget;
}
catch
{
method = invocation.GetConcreteMethod();
} var unitOfWorkAttr = _unitOfWorkOptions.GetUnitOfWorkAttributeOrNull(method);
if (unitOfWorkAttr == null || unitOfWorkAttr.IsDisabled)
{
//No need to a uow
invocation.Proceed();
return;
} //No current uow, run a new one
PerformUow(invocation, unitOfWorkAttr.CreateOptions());
} private void PerformUow(IInvocation invocation, UnitOfWorkOptions options)
{
if (invocation.Method.IsAsync())
{
PerformAsyncUow(invocation, options);
}
else
{
PerformSyncUow(invocation, options);
}
} private void PerformSyncUow(IInvocation invocation, UnitOfWorkOptions options)
{
using (var uow = _unitOfWorkManager.Begin(options))
{
invocation.Proceed();
uow.Complete();
}
} private void PerformAsyncUow(IInvocation invocation, UnitOfWorkOptions options)
{
var uow = _unitOfWorkManager.Begin(options); try
{
invocation.Proceed();
}
catch
{
uow.Dispose();
throw;
} if (invocation.Method.ReturnType == typeof(Task))
{
invocation.ReturnValue = InternalAsyncHelper.AwaitTaskWithPostActionAndFinally(
(Task) invocation.ReturnValue,
async () => await uow.CompleteAsync(),
exception => uow.Dispose()
);
}
else //Task<TResult>
{
invocation.ReturnValue = InternalAsyncHelper.CallAwaitTaskWithPostActionAndFinallyAndGetResult(
invocation.Method.ReturnType.GenericTypeArguments[0],
invocation.ReturnValue,
async () => await uow.CompleteAsync(),
exception => uow.Dispose()
);
}
}
}

  首先也是看这个类的注释:This interceptor is used to manage database connection and transactions.顾名思义就是这个拦截器是为了管理数据库的连接和事物操作的,在这个类的构造函数中默认注入了两个关键的类型,IUnitOfWorkManager和IUnitOfWorkDefaultOptions这两个一个用于管理UnitOfWork,另一个用于配置UnitOfWork,在我们的系统中,当我们调用带UnitOfWork特性的方法时,首先就会将该方法挂起,然后执行对应的拦截器的Intercept(IInvocation invocation)这个方法,在这个方法中首先会判断当前执行方法是否定义过自定义的UnitOfWork属性或者是符合特定规则的类型,关于这个类型上面也已经提到过,这里不再赘述仅仅看看其内部实现原理。

public static UnitOfWorkAttribute GetUnitOfWorkAttributeOrNull(this IUnitOfWorkDefaultOptions unitOfWorkDefaultOptions, MethodInfo methodInfo)
{
var attrs = methodInfo.GetCustomAttributes(true).OfType<UnitOfWorkAttribute>().ToArray();
if (attrs.Length > 0)
{
return attrs[0];
} attrs = methodInfo.DeclaringType.GetTypeInfo().GetCustomAttributes(true).OfType<UnitOfWorkAttribute>().ToArray();
if (attrs.Length > 0)
{
return attrs[0];
} if (unitOfWorkDefaultOptions.IsConventionalUowClass(methodInfo.DeclaringType))
{
return new UnitOfWorkAttribute(); //Default
} return null;
}

  通过这个方法我们就能够获取当前方法的自定义的UnitOfWorkAttribute属性,在获取了这个属性后,我们还需要判断该UnitOfWorkAttribute中的IsDisabled是否为true,如果为true的话那么就让该方法执行不再执行后面的一些操作了,所以这里ABP也给我们提供了一种不使用UnitOfWork特性的方法那就是定义UnitOfWorkAttribute的IsDisable属性,具体怎么使用呢?请看下面的示例。

[UnitOfWork(IsDisabled = true)]
public virtual void RemoveFriendship(RemoveFriendshipInput input)
{
_friendshipRepository.Delete(input.Id);
}

  在执行完这些判断的过程以后就是最关键的PerformUow这个方法了,在这个方法中会根据当前方法是否是异步方法分为两个过程,这里我仅仅使用同步的方法来进行说明这个过程到底是怎么样的?

private void PerformSyncUow(IInvocation invocation, UnitOfWorkOptions options)
{
using (var uow = _unitOfWorkManager.Begin(options))
{
invocation.Proceed();
uow.Complete();
}
}

  这个方法有没有非常熟悉,这个就是我们需要将我们执行的方法包装在一个Begin和一个Complete方法中,从而来完成整个工作单元的过程,在ABP中的官方文档中也提到了这种加入工作单元的方式,这里也可以看看这个示例。

public class MyService
{
private readonly IUnitOfWorkManager _unitOfWorkManager;
private readonly IPersonRepository _personRepository;
private readonly IStatisticsRepository _statisticsRepository; public MyService(IUnitOfWorkManager unitOfWorkManager, IPersonRepository personRepository, IStatisticsRepository statisticsRepository)
{
_unitOfWorkManager = unitOfWorkManager;
_personRepository = personRepository;
_statisticsRepository = statisticsRepository;
} public void CreatePerson(CreatePersonInput input)
{
var person = new Person { Name = input.Name, EmailAddress = input.EmailAddress }; using (var unitOfWork = _unitOfWorkManager.Begin())
{
_personRepository.Insert(person);
_statisticsRepository.IncrementPeopleCount(); unitOfWork.Complete();
}
}
}

  这个就是采用注入IUnitOfWorkManager的方式来完成工作单元的操作的,但是个人还是建议没有特别的目的还是自定义UnitOfWork属性比较好。在下一篇我会深入到UnitOfWorkManager中去看这个Begin和Complete方法到底做了些什么?需要关注请点击这里

  最后,点击这里返回整个ABP系列的主目录。

ABP拦截器之UnitOfWorkRegistrar(一)的更多相关文章

  1. ABP拦截器之UnitOfWorkRegistrar(二)

    在上面一篇中我们主要是了解了在ABP系统中是如何使用UnitOfWork以及整个ABP系统中如何执行这些过程的,那么这一篇就让我们来看看UnitOfWorkManager中在执行Begin和Compl ...

  2. ABP拦截器之AuthorizationInterceptor

    在整体介绍这个部分之前,如果对ABP中的权限控制还没有一个很明确的认知,请先阅读这篇文章,然后在读下面的内容. AuthorizationInterceptor看这个名字我们就知道这个拦截器拦截用户一 ...

  3. ABP中的拦截器之ValidationInterceptor(上)

    从今天这一节起就要深入到ABP中的每一个重要的知识点来一步步进行分析,在进行介绍ABP中的拦截器之前我们先要有个概念,到底什么是拦截器,在介绍这些之前,我们必须要了解AOP编程思想,这个一般翻译是面向 ...

  4. (实用篇)浅谈PHP拦截器之__set()与__get()的理解与使用方法

    "一般来说,总是把类的属性定义为private,这更符合现实的逻辑. 但是,对属性的读取和赋值操作是非常频繁的,因此在PHP5中,预定义了两个函数"__get()"和&q ...

  5. Java过滤器与SpringMVC拦截器之间的关系与区别

    今天学习和认识了一下,过滤器和SpringMVC的拦截器的区别,学到了不少的东西,以前一直以为拦截器就是过滤器实现的,现在想想还真是一种错误啊,而且看的比较粗浅,没有一个全局而又细致的认识,由于已至深 ...

  6. PHP拦截器之__set()与__get()的理解与使用

    “一般来说,总是把类的属性定义为private,这更符合现实的逻辑.但是,对属性的读取和赋值操作是非常频繁的,因此在PHP5中,预定义了两个函数“__get()”和“__set()”来获取和赋值其属性 ...

  7. PHP拦截器之__set()与__get()的理解与使用方法

    “一般来说,总是把类的属性定义为private,这更符合现实的逻辑.   但是,对属性的读取和赋值操作是非常频繁的,因此在PHP5中,预定义了两个函数“__get()”和“__set()”来获取和赋值 ...

  8. ABP中的拦截器之EntityHistoryInterceptor

    今天我们接着之前的系列接着来写另外一种拦截器EntityHistoryInterceptor,这个拦截器到底是做什么的呢?这个从字面上理解是实体历史?这个到底是什么意思?带着这个问题我们来一步步去分析 ...

  9. ABP中的拦截器之AuditingInterceptor

    在上面两篇介绍了ABP中的ValidationInterceptor之后,我们今天来看看ABP中定义的另外一种Interceptor即为AuditingInterceptor,顾名思义就是一种审计相关 ...

随机推荐

  1. MySQL查询执行的基础——查询优化处理

    查询的生命周期的下一步是将一个SQL转换成一个可执行计划,MySQL再按照这个计划和存储引擎进行交互 语法解析器和预处理 首先,MySQL通过关键词将SQL语句进行解析,并生成一颗对应的"解 ...

  2. 微信小程序(二)登录授权实现

    相对于上一节,这一节主要是动态获取数据,主要是对登陆信息的接收,以及页面获取授权按钮的相对相应(未授权时,显示,授权后不显示) 关键在于状态值的判断,以及对页面的不同响应(m-->v) wxml ...

  3. FormData 对象上传二进制文件

    使用jQuery 利用 FormData 上传文件:http://harttle.com/2016/07/04/jquery-file-upload.html     通过FormData对象可以组装 ...

  4. 测者的测试技术手册:揭开java method的一个秘密--巨型函数

    揭开java method的一个秘密:巨型函数 相信,很多人都不知道Java的Method的上限为64K.本文将超过这个上限的函数叫做巨型函数. 巨型函数的问题 1.如果代码超过了这个限制,Java编 ...

  5. 关于在Python2中使用列表推导式会遇到的问题

    摘自<流畅的Python>第二部分第二章2.2 Python 2.x 中,在列表推导中 for 关键词之后的赋值操作可能会影响列表推导上下文中的同名变量.像下面这个 Python 2.7 ...

  6. [20190415]10g下那些latch是共享的.txt

    [20190415]10g下那些latch是共享的.txt http://andreynikolaev.wordpress.com/2010/11/23/shared-latches-by-oracl ...

  7. js实现表格无缝滚动效果

    <!doctype html> <html> <head> <meta charset="utf-8"> <title> ...

  8. python3 dict(字典)

    clear(清空字典内容) stu = { 'num1':'Tom', 'num2':'Lucy', 'num3':'Sam', } print(stu.clear()) #输出:None copy( ...

  9. DRF项目创建流程(1)

    一 web应用模式 前后端不分离 前后端分离 二 RESTFUL API规范 REST全称是Representational State Transfer,中文意思是表述(编者注:通常译为表征)性状态 ...

  10. vue 快速入门、常用指令(1)

    1. vue.js的快速入门使用 1.1 vue.js库的下载 vue.js是目前前端web开发最流行的工具库之一,由尤雨溪在2014年2月发布的. 官方网站 中文:https://cn.vuejs. ...