ABP拦截器之UnitOfWorkRegistrar(一)
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(一)的更多相关文章
- ABP拦截器之UnitOfWorkRegistrar(二)
在上面一篇中我们主要是了解了在ABP系统中是如何使用UnitOfWork以及整个ABP系统中如何执行这些过程的,那么这一篇就让我们来看看UnitOfWorkManager中在执行Begin和Compl ...
- ABP拦截器之AuthorizationInterceptor
在整体介绍这个部分之前,如果对ABP中的权限控制还没有一个很明确的认知,请先阅读这篇文章,然后在读下面的内容. AuthorizationInterceptor看这个名字我们就知道这个拦截器拦截用户一 ...
- ABP中的拦截器之ValidationInterceptor(上)
从今天这一节起就要深入到ABP中的每一个重要的知识点来一步步进行分析,在进行介绍ABP中的拦截器之前我们先要有个概念,到底什么是拦截器,在介绍这些之前,我们必须要了解AOP编程思想,这个一般翻译是面向 ...
- (实用篇)浅谈PHP拦截器之__set()与__get()的理解与使用方法
"一般来说,总是把类的属性定义为private,这更符合现实的逻辑. 但是,对属性的读取和赋值操作是非常频繁的,因此在PHP5中,预定义了两个函数"__get()"和&q ...
- Java过滤器与SpringMVC拦截器之间的关系与区别
今天学习和认识了一下,过滤器和SpringMVC的拦截器的区别,学到了不少的东西,以前一直以为拦截器就是过滤器实现的,现在想想还真是一种错误啊,而且看的比较粗浅,没有一个全局而又细致的认识,由于已至深 ...
- PHP拦截器之__set()与__get()的理解与使用
“一般来说,总是把类的属性定义为private,这更符合现实的逻辑.但是,对属性的读取和赋值操作是非常频繁的,因此在PHP5中,预定义了两个函数“__get()”和“__set()”来获取和赋值其属性 ...
- PHP拦截器之__set()与__get()的理解与使用方法
“一般来说,总是把类的属性定义为private,这更符合现实的逻辑. 但是,对属性的读取和赋值操作是非常频繁的,因此在PHP5中,预定义了两个函数“__get()”和“__set()”来获取和赋值 ...
- ABP中的拦截器之EntityHistoryInterceptor
今天我们接着之前的系列接着来写另外一种拦截器EntityHistoryInterceptor,这个拦截器到底是做什么的呢?这个从字面上理解是实体历史?这个到底是什么意思?带着这个问题我们来一步步去分析 ...
- ABP中的拦截器之AuditingInterceptor
在上面两篇介绍了ABP中的ValidationInterceptor之后,我们今天来看看ABP中定义的另外一种Interceptor即为AuditingInterceptor,顾名思义就是一种审计相关 ...
随机推荐
- PHP中使用 fsockopen curl 模拟异步处理
PHP它最大缺点就是无法实现多线程管理,其程序的执行都是从头到尾,按照逻辑一路执行下来,不可能出现分支,这一点是限制php在主流程序语言中往更高级的语言发展的原因之一. 在PHP中我们有的时候其实希望 ...
- JAVA程序员面试30问(附带答案)
第一,谈谈final, finally, finalize的区别. 最常被问到.final修饰符(关键字)如果一个类被声明为final,意味着它不能再派生出新的子类,不能作为父类被继承.因此一个类不能 ...
- SpringDay01
Spring的控制反转 Spring的依赖注入 多种注入方式 多种属性的注入方式 <bean id="userDao" class="dao.UserDaoImpl ...
- 手机端input[type=date]的placeholder不起作用
<div class="input clearfix"> <label class="fl">起始日期</label> &l ...
- 【代码笔记】Web-JavaScript-JavaScript JSON
一,效果图. 二,代码. <!DOCTYPE html> <html> <head> <meta charset="utf-8"> ...
- WGS84地理坐标系下,进行坐标运算
经纬度坐标本身是不能直接运算的.原因是:经纬度坐标并非是直角坐标系.纬线圈间隔均匀,经线圈越靠近两级越密,如下图: 现在有个需求,已知两点和两点处射线斜率,求交点坐标. 虽然地球整体是个圆,但是局部地 ...
- arcgis for js学习之Draw类
arcgis for js学习之Draw类 <!DOCTYPE html> <html> <head> <meta http-equiv="Cont ...
- Android为TV端助力 播放视频卡顿问题
问题分析: 1.连接服务器,ping IP 看看有没有丢包 2.写一个只有mediaplayer的Demo,放到同款的盒子或者电视,保证网咯也是一样的情况下,看看Demo卡不卡 如果一直不卡,那有可能 ...
- MongoDB:数据库介绍与基础操作
二.部署在本地服务器 在上次的学习过程中,我们主要进行了MongoDB运行环境的搭建和可视化工具的安装.此次我们将学习MongoDB有关的基本概念和在adminmongo上的基本操作.该文档中的数据库 ...
- Mysql学习路线
本文内容: mysql学习路线 首发日期:2018-04-19 由于现在很多都是有api了,很多问题都转接到编程语言上来处理了,所以这篇mysql之路仅仅是作为“了解”之用.不深究mysql. 很多东 ...