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的ArrayList源码摘要
ArrayList本质上是一组对象数组,ArrayList有三种构造方法 1.指定长度创建ArrayList,2.默认长度为10创建.3,用旧的集合创建一个ArrayList. 对ArrayList的 ...
- nodejs 搭建简易服务器
www文件夹下 template文件夹下 server.js代码: const express=require('express'); const static=require('express-st ...
- 微信小程序解密得到unoinid和手机号 (开放数据的校验和解密 获取手机号)
实际测试 两种方法都可以: 第一种方法: public static string DecodeUserInfo(string encryptedData, string iv, string cod ...
- jsp内置对象的作用范围
内置对象的作用范围是指每个内置对象的某个实例在多长时间和多大的范围中有效,即在什么样的范围内可以有效地访问同一个对象实例. 在javax.servlet.jsp.PageContext的类中定义了4个 ...
- JS、CSS中的相对路径
css中url(../images/1.jpg)路径是相对于index.css的 js中url(images/1.jpg)路径是相对于index.html的,并不是相对于index.js
- 基础环境系列:Apache2.4.37
一.安装 进入官网http://www.apache.org/,滑至最下方,排名第一的HTTP Server就是我们需要的. 当前时间的最新版本是2.4.37.呃……并没有msi版本,我们选择最后一个 ...
- bootstrap-treeview 在 bootstrap 4 不兼容解决办法及使用
bootstrap-treeview 是bootstrap的一个树形插件,插件依赖: bootstrap/3.3.7 jquery/3.3.1 经过验证,它不可以在 bootstrap 高于 3.3. ...
- java 中文乱码以及转码
查看此文章需要对字符集编码有一定的认识:任意门:字符集编码基础 一.字符串的内部表示? 重点:字符串在java(指在JVM中.在内存中)中统一用unicode表示( 即utf-16 LE) , 下面解 ...
- Zabbix监控USG6300防火墙及交换机
1.登录防火墙直接在web上面配置SNMP,只读团体名.读写团体名.Trap接收主机.安全名,点击应用完成防火墙上面的SNMP配置,如果你的命令行敲得6,可以使用命令行敲,配置效果一样,交换机没有这么 ...
- new 和 newInstance 的区别
初始化一个类,生成一个实例的时候:newInstance() 和 new 有什么区别? 用newInstance与用new是区别的,区别在于创建对象的方式不一样,前者是使用类加载机制,那么为什么会有两 ...