按照单一职责的原则,拦截器只负责需要的拦截操作的执行,至于它采用何种方式应用到目标方法上,以及它在整个拦截器管道中的位置则属于“拦截器注册”的范畴。Dora.Interception提供了几种典型的注册方法,用户也可以根据自己的需求实现自己的注册方式。

一、IInterceptorProvider

一般来说,每一个拦截器类型都对应着一个IInterceptorProvider实现类型,后者利用其Use方法负责将前者放置到拦截器管道指定的位置。如下面的代码所示,IInterceptorProvider还具有一个布尔类型的AllowMultiple属性,它表示相同类型的多一个拦截器对象是否可以同时应用到同一个方法上。如果该属性返回False,Dora.Interception只会选择其中一个。

public interface IInterceptorProvider
{
void Use(IInterceptorChainBuilder builder);
bool AllowMultiple { get; }
}

IInterceptorProvider的Use方法具有一个IInterceptorChainBuilder类型的参数。IInterceptorChainBuilder类似于ASP.NET Core中的IApplicationBuilder,我们将InterceptorDelegate 对象表示的拦截器根据指定的位置(order属性)注册到IInterceptorChainBuilder对象上,并最终利用其Build方法构建一个通过InterceptorDelegate 表示的拦截器管道。

public interface IInterceptorChainBuilder
{
IServiceProvider ServiceProvider { get; }
IInterceptorChainBuilder Use(InterceptorDelegate interceptor, int order);
InterceptorDelegate Build();
IInterceptorChainBuilder New();
}

由于大部分情况下的拦截器都是根据约定定义的,所以我们为IInterceptorChainBuilder 定义了如下的扩展方法。

public static class InterceptorChainBuilderExtensions
{
public static IInterceptorChainBuilder Use<TInterceptor>(this IInterceptorChainBuilder builder, int order, params object[] arguments)
public static IInterceptorChainBuilder Use(this IInterceptorChainBuilder builder, Type interceptorType, int order, params object[] arguments);
public static IInterceptorChainBuilder Use(this IInterceptorChainBuilder builder, object interceptor, int order);
}

二、基于特性的拦截器注册方式

通过在类型和方法/属性成员上标注对应特性是最常用的拦截器注册方式,这样的特性一般继承自InterceptorAttribute。如下面的代码片段所示,InterceptorAttribute实现了IInterceptorProvider接口,它的定义了Order属性来表示注册拦截器最终在管道中的位置。AllowMultiple 属性来源于应用到当前特性类型上的AttributeUsageAttribute特性的同名属性。

[AttributeUsage(AttributeTargets.Class | AttributeTargets.Method | AttributeTargets.Property, AllowMultiple = false)]
public abstract class InterceptorAttribute : Attribute, IInterceptorProvider
{
public int Order { get; set; }
public bool AllowMultiple {get;}
public abstract void Use(IInterceptorChainBuilder builder);
}

对于在《拦截器的设计》中定义了那个FoobarInterceptor,我们可以将对应的特性定义成如下的形式。

[AttributeUsage(AttributeTargets.Class | AttributeTargets.Method | AttributeTargets.Property, AllowMultiple = false)]
public class FoobarAttribute: InterceptorAttribute
{
private readonly string _baz;
public FoobarAttribute (string baz) => _baz = baz;
public override void Use(IInterceptorChainBuilder builder)=> builder.Use<FoobarInterceptor>(Order, _baz);
}

三、拦截器和特性合二为一

如果嫌将拦截器和对应的特性分开定义太繁琐,我们可以将它们合二为一。对于在《拦截器的设计》中定义了那个FoobarInterceptor可以定义成如下的形式。

[AttributeUsage(AttributeTargets.Class | AttributeTargets.Method | AttributeTargets.Property, AllowMultiple = false)]
public class FoobarAttribute:InterceptorAttribute
{
private readonly string _baz;
public FoobarAttribute(string baz)=>_baz = baz; public async InvokeAsync(InvocationContext context, IFoo foo, IBar bar)
{
await PreInvokeAsync();
await context.ProceedAsync();
await PostInvokeAsync();
} public override void Use(IInterceptorChainBuilder builder) => builder.Use(this, Order, _baz);
}

四、NonInterceptableAttribute

如果某个类型或者方法不应该被拦截,我们可以在上面标注一个NonIntercetableAttribute。以如下这个Foobarbaz类型为例,由于FoobarInterceptorAttribute标注在类型,意味着对应的拦截器会应用到所有可被拦截的虚方法上。如果Baz方法不应该被拦截,应该在上面标注NonIntercetableAttribute特性。

[FoobarInterceptor]
public class Foobarbaz
{
public virtual Foo();
public virtual Bar();
[NonInterceptable]
public virtual Baz();
}

除了利用NonIntercetableAttribute屏蔽所有的拦截器之外,我们还可以利用它屏蔽指定类型的拦截器。如下面的代码片段所示,Foobarbaz类型上标注了三个InterceptorAttribute,但是方法Baz只需要BazInterceptorAttribute,我们可以利用NonIntercetableAttribute特性将其他两个屏蔽掉。

[FooInterceptor]
[BarInterceptor]
[BazInterceptor]
public class Foobarbaz
{
public virtual Foo();
public virtual Bar();
[NonInterceptable(typeof(FooInterceptorAttribute), typeof(BarInterceptorAttribute), )]
public virtual Baz();
}

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]: 自定义拦截器注册方式

最新文章

  1. Windows中搭建Redis集群
  2. gulp教程之gulp-uglify
  3. css3 filter属性在项目中的应用
  4. mvc5+ef6+Bootstrap 项目心得--WebGrid
  5. C-全局变量与局部变量
  6. pre标签避免一行过长打破格局
  7. 【转】Android M新控件之AppBarLayout,NavigationView,CoordinatorLayout,CollapsingToolbarLayout的使用
  8. asp 回发的时候样式变化
  9. [转]使用ADO.NET访问Oracle存储过程
  10. POJ2242 The Circumference of the Circle(几何)
  11. qt 多线程之间通讯
  12. 什么是LeapMotion
  13. apache 安装[转]
  14. 华为路由器AR1220F-S的端口映射NAT配置(拨号光纤上网)
  15. 2019-02-10 扩展Python控制台实现中文反馈信息
  16. 应用负载均衡之LVS(五):lvs和nginx的wrr加权调度算法规律分析
  17. 为什么java的类是单继承的,接口是多继承的
  18. linux centos 基本命令
  19. 使用synchronized(非this对象)同步代码块解决脏读问题
  20. e.pageX、e.clientX、e.screenX、e.offsetX的区别以及元素的一些CSS属性

热门文章

  1. 【论文阅读】CornerNet: Detecting Objects as Paired Keypoints
  2. Magicodes.IE之导入学生数据教程
  3. 2019-10-23:渗透测试,基础学习,DVWA,Medium和Hight级别sql注入
  4. 使用FastReport报表工具实现信封套打功能
  5. 自定制页面跳转时携带原搜索参数的URL
  6. c语言l博客作业02
  7. python基础-并发编程part01
  8. list列表操作
  9. Java数组与C/C++数组的区别
  10. 《Windows内核安全与驱动开发》 3.1 字符串操作