【Autofac打标签模式】Aspect拦截器

【 Autofac打标签模式】开源DI框架扩展地址:

https://github.com/yuzd/Autofac.Annotation/wiki

 

前提条件

自己new一个对象不能实现拦截器功能,必须得从DI容器拿到的对象才能具备拦截器功能 可以参考 我写的文章介绍

拦截器原理简单介绍

用了Castle.Core组件 把你想要实现拦截器的目标类生成一个代理类。 然后织入拦截器,有2种方式

  1. class + 方法为virtual的方式
    • 这种方式需要 从容器中是根据一个classType来获取到目标实例
  2. interface + 方法重写的方式
    • 这种方式需要 从容器中是根据一个interfaceType来获取到目标实例

拦截器开关

在你想要实现拦截的目标类上打上 【Aspect】标签,如上面的解释,Aspect标签可以根据InterceptorType属性值设定你是哪种方式的拦截器

InterceptorType属性解释
Class 使用class的虚方法模式 【默认方式】
Interface 使用接口模式

目的是打个标签就能够拦截目标方法

使得我们自定义的方法能够

  • 在指定的目标方法执行之前先执行(比如参数校验)
  • 或者在指定的目标方法执行之后执行(比如说检验返回值,或其他收尾工作)
  • 或者环绕目标的方法,比如事务:TransactionScope或者记录方法执行的时间
拦截器标签拦截器类型使用说明
AspectBeforeAttribute(抽象标签类) 前置拦截器 重写Before方法
AspectAfterAttribute(抽象标签类) 后置拦截器 重写After方法
AspectAroundAttribute(抽象标签类) 前置+后置拦截器 重写Before和重写After方法
PointcutAttribute(抽象标签类) 环绕拦截器 重写OnInvocation方法

拦截器的方法参数 AspectContext 属性说明

名称说明
ComponentContext DI容器,可以从中取得你已注册的实例
InvocationContext 执行上下文,例如被拦截的MethodInfo ,Name, Parameters,ReturnType等
Exception 异常信息,这个在前置拦截器是肯定为null,在后置拦截器中如果被拦截的方法出现了异常就能通过这个字段拿到异常信息

Exception说明

前置拦截器若抛了没有被catch住的异常

  • 如果有后置拦截器,可以在AspectContext的Exception字段获取。
  • 如果没有后置拦截器则抛出

前置拦截器

  1. 首先要自己写一个类继承 前置拦截器AspectBeforeAttribute(抽象标签类)
  2. 实现该抽象类的Before方法

image

1. 然后在被拦截方法的所在类上打上 【Aspect】标签;

2. 被拦截方法上打上 【TestHelloBefor】标签

3. 被拦截方法需要有 virtual 关键字

image

前置拦截器方法的执行顺序为:先执行 TestHelloBefor的Before方法再执行你的Say方法

后置拦截器

  1. 首先要自己写一个类继承后置拦截器AspectAfterAttribute(抽象标签类)
  2. 实现该抽象类的After方法

image

1. 然后在被拦截方法的所在类上打上 【Aspect】标签;

2. 被拦截方法上打上 【TestHelloAfter】标签

3. 被拦截方法需要有 virtual 关键字

image

后置拦截器方法的执行顺序为:先执行你的SayAfter方法再执行 TestHelloAfter的After方法

前置+后置拦截器

  1. 首先要自己写一个类继承拦截器AspectAroundAttribute(抽象标签类)
  2. 实现该抽象类的Before 和 After方法

image

1. 然后在被拦截方法的所在类上打上 【Aspect】标签;

2. 被拦截方法上打上 【TestHelloArround】标签

3. 被拦截方法需要有 virtual 关键字

image

方法的执行顺序为:

  1. 先执行TestHelloArround的Before方法
  2. 然后执行你的SayArround方法
  3. 再执行 先执行TestHelloArround的After方法

环绕拦截器的前置+后置的另外一种方式(更灵活)

注意:OnInvocation方法除了AspectContext参数以外 还有一个 AspectDelegate _next 参数, 如果只有一个环绕拦截器的话,那么这个参数就是被拦截方法的本体, 如果有多个环绕拦截器的话,那么最后一个就是被拦截方法的本体。

  1. 首先要自己写一个类继承拦截器PointcutAttribute(抽象标签类)
  2. 实现该抽象类的OnInvocation方法

image

1. 然后在被拦截方法的所在类上打上 【Aspect】标签;

2. 被拦截方法上打上 【TransactionInterceptor】标签

3. 被拦截方法需要有 virtual 关键字

image

方法的执行顺序为:

  1. 先执行TransactionInterceptor的OnInvocation方法
  2. 然后TransactionInterceptor的OnInvocation方法里面执行的 await _next(aspectContext); 就会执行被拦截方法TestInterceptor;

如果有多个环绕拦截器的话,如下图:

image

image

如上图 代码的执行顺序为:

image

posted @ 2019-10-27 13:04  俞正东  阅读(952)  评论(2编辑  收藏  举报