设为首页 加入收藏

TOP

[Abp vNext 源码分析] - 3. 依赖注入与拦截器(三)
2019-09-17 18:45:30 】 浏览:131
Tags:Abp vNext 源码 分析 依赖 注入 拦截
可以传入 ABP vNext 定义的 IAbpInterceptor 作为其泛型参数。

public class CastleAbpInterceptorAdapter<TInterceptor> : IInterceptor
    where TInterceptor : IAbpInterceptor
{
    
}

Castle 的拦截器也会有一个 Intercept() 方法,该方法将在被拦截方法执行的时候触发。在触发之后,会根据当前方法的定义进行不同的操作,这里异步方法和同步方法处理逻辑是不一样的。

public void Intercept(IInvocation invocation)
{
    var proceedInfo = invocation.CaptureProceedInfo();

    var method = invocation.MethodInvocationTarget ?? invocation.Method;

    // 判断执行的方法是否是异步方法。
    if (method.IsAsync())
    {
        InterceptAsyncMethod(invocation, proceedInfo);
    }
    else
    {
        InterceptSyncMethod(invocation, proceedInfo);
    }
}

这里我们以异步方法为例,其内部又会根据方法的返回值是否是 Task 进行不同的操作,因为如果是泛型的 Task,说明该异步方法是有返回值的,所以处理逻辑也不一样。

private void InterceptAsyncMethod(IInvocation invocation, IInvocationProceedInfo proceedInfo)
{
    if (invocation.Method.ReturnType == typeof(Task))
    {
        invocation.ReturnValue = MethodExecuteWithoutReturnValueAsync
            .Invoke(this, new object[] { invocation, proceedInfo });
    }
    else
    {
        invocation.ReturnValue = MethodExecuteWithReturnValueAsync
            .MakeGenericMethod(invocation.Method.ReturnType.GenericTypeArguments[0])
            .Invoke(this, new object[] {invocation, proceedInfo});
    }
}

进一步解析在返回类型为 Task 时,它所调用的方法。

private async Task ExecuteWithoutReturnValueAsync(IInvocation invocation, IInvocationProceedInfo proceedInfo)
{
    // 注意这里,该用法在之前的 C# 多线程学习笔记文章有说过,作用是出让当前核心给其他线程。
    await Task.Yield();

    // 调用真实的拦截器,根据传入的方法调用模型去拦截真实的方法。
    await _abpInterceptor.InterceptAsync(
        new CastleAbpMethodInvocationAdapter(invocation, proceedInfo)
    );
}

从上述代码可以得知,ABP vNext 的拦截器动作现在被包裹在一个 Castle 拦截器内部进行的。

那么,我们的 Castle.Core 拦截器在什么时候与类型进行绑定的呢,每个拦截器又是如何与特性的类型进行注册的呢?这里我以审计日志拦截器为例,看一下它在系统当中是如何注册,并被使用的。

审计日志相关的代码存放在 Volo.Abp.Auditing 库中,我们找到 AuditingInterceptor 类型,查看其定义可以看到它也是继承自 AbpInterceptor 抽象基类。

public class AuditingInterceptor : AbpInterceptor, ITransientDependency
{
    
}

接着我们根据名字找到了拦截器的注册工具类 AuditingInterceptorRegistrar,在类型的定义当中 ShouldIntercept()ShouldAuditTypeByDefault() 根据传入的 Type 类型,根据特定的逻辑决定是否为该类型关联审计日志拦截器。

private static bool ShouldIntercept(Type type)
{
    if (ShouldAuditTypeByDefault(type))
    {
        return true;
    }

    // 如果类型的任意方法启用了 Auditied 特性,则应用拦截器。
    if (type.GetMethods().Any(m => m.IsDefined(typeof(AuditedAttribute), true)))
    {
        return true;
    }

    return false;
}

public static bool ShouldAuditTypeByDefault(Type type)
{
    // 判断类型是否使用了 Audited 特性,使用了则应用审计日志拦截器。
    if (type.IsDefined(typeof(AuditedAttribute), true))
    {
        return true;
    }

    // 判断类型是否使用了 DisableAuditing 特性,使用了则不关联拦截器。
    if (type.IsDefined(typeof(DisableAuditingAttribute), true))
    {
        return false;
    }

    // 如果类型实现了 IAuditingEnabled 接口,则启用拦截器。
    if (typeof(IAuditingEnabled).IsAssignableFrom(type))
    {
        return true;
    }

    return false;
}

我们这里需要关注的是 RegisterIfNeeded() 方法,它在审计日志模块的预加载方法就被添加到了一个 ServiceRegistrationActionList 集合当中,这个集合会在后面 AutoFac 进行类型注册的时候被使用。

public static void RegisterIfNeeded(IOnServiceRegistredContext context)
{
    // 如果类型允许被审计日志拦截器所拦截,则在类型关联的拦截器上下文当中添加审计日志拦截器。
    if (ShouldIntercept(context.ImplementationType))
    {
        context.Interceptors.TryAdd<AuditingInterceptor>();
    }
}
public override void PreConfigureServices(ServiceConfigurationContext context)
{
    // 将这个 Action 加入 List。
    context.Services.OnRegistred(AuditingInterceptorRegistrar.RegisterIfNeeded);
}
首页 上一页 1 2 3 4 5 6 7 下一页 尾页 3/7/7
】【打印繁体】【投稿】【收藏】 【推荐】【举报】【评论】 【关闭】 【返回顶部
上一篇本地Git仓库和Github仓库的关联 下一篇Asp .Net core 2 学习笔记(3) —..

最新文章

热门文章

Hot 文章

Python

C 语言

C++基础

大数据基础

linux编程基础

C/C++面试题目