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,顾名思义就是一种审计相关 ...
随机推荐
- Java学习笔记之——集合
集合是类,用来存储多个数据,有属性.方法 集合是一个可变数组,保存相同元素并且长度可变 1. 体系 (1)Collection:存储一个一个的值 Iterable: Iterable<T> ...
- Linux文件基本操作管理
这一篇总结Linux系统中文件和目录的创建,复制,移动和重命名,包括删除这些最常用的操作. 创建 1,创建目录 使用命令:mkdir 实践:在根目录下创建一个目录命名为mcgrady 2,创建文件 使 ...
- asp.net/wingtip/UI和导航
ASP.NET Web窗体可以让web应用创建动态内容.静态网页的知识和HTML.CSS一模一样,区别在于ASP.NET网页包括了ASP.NET可以识别并处理的服务器端的内容.对于静态页面(.html ...
- Python浅谈requests三方库
requests 三方库用于获取URL资源 1.GET请求访问一个页面 import requests r = requests.get('https://www.cnblogs.com/xqxacm ...
- Skywalking部署常见问题以及注意事项
Skywalking部署常见问题以及注意事项 Intro SkyWalking 创建与2015年,提供分布式追踪功能.从5.x开始,项目进化为一个完成功能的Application Performanc ...
- Yapi部署说明
1.环境搭建 确保 node 版本=> 7.6,请运行 node -v 查看版本号 确保 mongodb 版本 => 2.6,请运行 mongo --version 查看版本号 确保安装了 ...
- Python编写脚本(输出三星形状的‘*’符号)
环境:python3.* 心得:个人认为脚本非我强项,以下效果可以有更简单解决方案,纯属练习逻辑. 方案一: s=1 while s<=10: #这是决定多少列,起始为1,大循环一圈即加一,就是 ...
- AngularJS学习之旅—AngularJS Http(九)
1.AngularJS XMLHttpRequest $http 是 AngularJS 中的一个核心服务,用于读取远程服务器的数据. eg: // 简单的 GET 请求,可以改为 POST $htt ...
- JavaScript -- JSON.parse 函数 和 JSON.stringify 函数
JavaScript -- JSON.parse 函数 和 JSON.stringify 函数 1. JSON.parse 函数: 使用 JSON.parse 可将 JSON 字符串转换成对象. &l ...
- 【Python 24】52周存钱挑战4.0(函数)
1.案例描述 按照52周存钱法,存钱人必须在一年52周内,每周递存10元.例如,第一周存10元,第二周存20元,第三周存30元,直到第52周存520元. 记录52周后能存多少钱?即10+20+30+. ...