AOP框架Dora.Interception 3.0 [3]: 拦截器设计

对于所有的AOP框架来说,多个拦截器最终会应用到某个方法上。这些拦截器按照指定的顺序构成一个管道,管道的另一端就是针对目标方法的调用。从设计角度来将,拦截器和中间件本质是一样的,那么我们可以按照类似的模式来设计拦截器。

一、InvocationContext

我们为整个拦截器管道定义了一个统一的执行上下文,并将其命名为InvocationContext。如下面的代码片段所示,我们可以利用InvocationContext对象得到方法调用上下文的相关信息,其中包括两个方法(定义在接口和实现类型),目标对象、参数列表(含输入和输出参数)、返回值(可读写)。Properties 属性提供了一个自定义的属性容器,我们可以利用它来存放任意与当前方法调用上下文相关的信息。如果需要调用后续的拦截器或者目标方法(如果当前为最后一个拦截器),我们只需要直接调用ProceedAsync方法即可。

public abstract class InvocationContext
{
    public abstract MethodInfo Method { get; }
    public MethodInfo TargetMethod { get; }
    public abstract object Target { get; }
    public abstract object[] Arguments { get; }
    public abstract object ReturnValue { get; set; }
    public abstract IDictionary<string, object> Properties { get; }
    public Task ProceedAsync();
}

二、两个委托对象

既然所有的拦截器都是在同一个InvocationContext上下文中执行的,那么我们可以将任意的拦截操作定义成一个Func<InvocationContext, Task>对象。Func<InvocationContext, Task>对象不仅可以表示某项单一的拦截操作,实际上包括目标方法调用在内的整个拦截器管道都可以表示成一个Func<InvocationContext, Task>对象。由于这个委托的重要性,我们将它定义成如下这个InterceptDelegate类型。

public delegate Task InterceptDelegate(InvocationContext context);

如果以ASP.NET Core框架的请求处理管道作为类比,那么InvocationContext相当于HttpContext,而InterceptDelegate自然对应的就是RequestDelegate。我们知道ASP.NET Core框架将中间件表示成Func<RequestDelegate, RequestDelegate>对象,那么拦截器自然就可以表示成一个Func<InterceptDelegate, InterceptDelegate>。如果读者朋友对此不太理解,可以参阅我的文章《200行代码,7个对象——让你了解ASP.NET Core框架的本质》。由于拦截器的重要性,我们也将它定义成如下这个单独的InterceptorDelegate类型。

public delegate InterceptDelegate InterceptorDelegate(InterceptDelegate next);

三、基于约定的拦截器定义

Dora.Interception和ASP.NET Core采用几乎一致的设计。对于ASP.NET Core来说,虽然中间件最终是通过Func<InterceptDelegate, InterceptDelegate>表示的,但是我们可以将中间件定义成一个按照约定定义的类型。Dora.Interception同样支持基于约定的拦截器类型定义。

public class FoobarInterceptor
{
    private readonly IFoo _foo;
    private readonly IBar _bar;
    private readonly string _baz;

    public FoobarInterceptor(IFoo foo, IBar bar, string baz)
    {
        _foo = foo;
        _bar = bar;
        _baz = baz;
    }

    public async InvokeAsync(InvocationContext context)
    {
        await PreInvokeAsync();
        await context.ProceedAsync();
        await PostInvokeAsync();
    }
}

如上定义的FoobarInterceptor展现了一个典型的基于约定定义的拦截器类型,它体现了如下的约定:

  • 拦截器类型是一个实例类型(不能定义成静态类型);
  • 必须具有一个公共构造函数,其中可以定义任意参数。
  • 拦截操作定义在一个名为InvokeAsync的方法中,该方法的返回类型为Task,其中包含一个InvocationContext类型的参数。如果需要调用后续拦截器管道,需要显式调用InvocationContext上下文的ProceedAsync方法。

四、两种注入方式

由于拦截器最终是利用.NET Core的依赖注入框架提供的,所以依赖服务可以直接注入拦截器的构造函数中。但是就服务的生命周期来讲,拦截器本质上是一个Singleton服务,我们不应该将Scoped服务注入到它的构造函数中。如果具有针对Scoped服务注入的需要,我们应该将它注入到InvokeAsync方法中。

public class FoobarInterceptor
{
    private readonly string _baz;

    public FoobarInterceptor(string baz)
    {
        _baz = baz;
    }

    public async InvokeAsync(InvocationContext context, IFoo foo, IBar bar)
    {
        await PreInvokeAsync();
        await context.ProceedAsync();
        await PostInvokeAsync();
    }
}

当Dora.Interception在调用InvokeAsync方法的时候,它会利用当前Scope的IServiceProvider对象来提供其参数。对于ASP.NET Core应用来说,如果拦截器的执行在整个请求处理的调用链中,这个IServiceProvider对象就是当前HttpContext的RequestServices属性。如果当前IServiceProvider不存在,作为根的IServiceProvider对象会被使用。

AOP框架Dora.Interception 3.0 [1]: 编程体验
AOP框架Dora.Interception 3.0 [2]: 实现原理
AOP框架Dora.Interception 3.0 [3]: 拦截器设计
AOP框架Dora.Interception 3.0 [4]: 基于特性的拦截器注册
AOP框架Dora.Interception 3.0 [5]: 基于策略的拦截器注册
AOP框架Dora.Interception 3.0 [6]: 自定义拦截器注册方式

原文地址:https://www.cnblogs.com/artech/p/dora-interception-3-03.html

时间: 2024-10-13 16:16:35

AOP框架Dora.Interception 3.0 [3]: 拦截器设计的相关文章

AOP框架Dora.Interception 3.0 [4]: 基于特性的拦截器注册

按照单一职责的原则,拦截器只负责需要的拦截操作的执行,至于它采用何种方式应用到目标方法上,以及它在整个拦截器管道中的位置则属于“拦截器注册”的范畴.Dora.Interception提供了几种典型的注册方法,用户也可以根据自己的需求实现自己的注册方式. 一.IInterceptorProvider 一般来说,每一个拦截器类型都对应着一个IInterceptorProvider实现类型,后者利用其Use方法负责将前者放置到拦截器管道指定的位置.如下面的代码所示,IInterceptorProvid

AOP框架Dora.Interception 3.0 [1]: 编程体验

.NET Core正式发布之后,我为.NET Core度身定制的AOP框架Dora.Interception也升级到3.0.这个版本除了升级底层类库(.NET Standard 2.1)之外,我还对它进行大范围的重构甚至重新设计.这次重构大部分是在做减法,其目的在于使设计和使用更加简单和灵活,接下来我们就来体验一下在一个ASP.NET Core应用程序下如何使用Dora.Interception. 源代码下载实例1(Console)实例2(ASP.NET Core MVC + 注册可拦截服务)实

SpringMVC案例3----spring3.0项目拦截器、ajax、文件上传应用

依然是项目结构图和所需jar包图: watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvYmVuamFtaW5fd2h4/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/Center" > watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvYmVuamFtaW5fd2h4/font/5a6L5L2T/fontsize/400/fil

Web框架高级功能之模板、拦截器、Json、打包

类Flask框架实现 模板 <!DOCTYPE html> <html lang="en" xmlns="http://www.w3.org/1999/html"> <head> <meta charset="UTF-8"> <title>Title</title> </head> <body> <br>显示数据<\br> {{

springboot 2.0+ 自定义拦截器 静态资源问题

之前项目的springboot自定义拦截器使用的是继承WebMvcConfigurerAdapter重写常用方法的方式来实现的.静态文件不需要进行放行,springboot会自动帮你放行. springboot2.0之后如果想要自定义的话就不可以了,需要手动放行静态资源.此处我是实现了WebMvcConfigurer来自定义拦截器(根据需求也可以继承WebMvcConfigurationSupport,此处不再赘述).下面是实现代码 @Configuration public class MyM

关于Spring boot2.0+配置拦截器拦截静态资源的问题

第一次遇到这个问题的时候,简直是一脸蒙逼,写了一个拦截器以后,静态资源就不能访问了,到处查找才知道是版本问题 解决办法: 第一步:定义一个类实现 实现WebMvcConfigurer的类中拦截器中添加放行资源处添加静态资源文件路径: @Override public void addInterceptors(InterceptorRegistry registry) { registry.addInterceptor(sessionInterceptor).addPathPatterns("/&

springboot2.0 使用拦截器后,导致静态文件访问不到的解决方案

1 package com.leenleda.ward.tv.admin.interceptor; 2 3 import com.leenleda.ward.tv.common.config.LeenledaConfig; 4 import org.springframework.beans.factory.annotation.Autowired; 5 import org.springframework.context.annotation.Configuration; 6 import o

SpringBank 开发日志 一种简单的拦截器设计实现

当交易由Action进入Service之前,需要根据不同的Service实际负责业务的不同,真正执行Service的业务逻辑之前,做一些检查工作.这样的拦截器应该是基于配置的,与Service关联起来的. /** * @author wangxin * @contact [email protected] * @date Jul 22, 2017 * @Description: 所有TransactionController的抽象父类,主要作用为以一种低耦合的方式调用Service */ pub

Spring AOP原理及拦截器

原理 AOP(Aspect Oriented Programming),也就是面向方面编程的技术.AOP基于IoC基础,是对OOP的有益补充. AOP将应用系统分为两部分,核心业务逻辑(Core business concerns)及横向的通用逻辑,也就是所谓的方面Crosscutting enterprise concerns,例如,所有大中型应用都要涉及到的持久化管理(Persistent).事务管理(Transaction Management).安全管理(Security).日志管理(L