-
Notifications
You must be signed in to change notification settings - Fork 52
4.Aspect拦截器
自己new一个对象不能实现拦截器功能,必须得从DI容器拿到的对象才能具备拦截器功能 可以参考 我写的文章介绍
用了Castle.Core组件 把你想要实现拦截器的目标类生成一个代理类。 然后织入拦截器,有2种方式
- 类拦截器: class + 方法为virtual的方式
- 这种方式需要 从容器中是根据一个classType来获取到目标实例
- 接口型拦截器: interface + 方法重写的方式
- 这种方式需要 从容器中是根据一个interfaceType来获取到目标实例
ps: 图片参考了蒋老师的
如果你的class里面存在任一方法上面有打上下方列的拦截器标签,那么就会被框架认为这个class需要被代理包装,还可以根据InterceptorType属性值设定你是哪种方式的拦截器
InterceptorType属性 | 解释 |
---|---|
Class | 使用class的虚方法模式 【默认方式】 |
Interface | 使用接口模式 |
使得我们自定义的方法能够
- 在指定的目标方法执行之前先执行(比如参数校验)
- 或者在指定的目标方法执行之后执行(比如说检验返回值,或其他收尾工作)
- 或者环绕目标的方法,比如日志or事务:TransactionScope或者记录方法执行的时间或者日志
拦截器标签 | 拦截器类型 | 使用说明 |
---|---|---|
AspectArround(抽象标签类) | 环绕拦截 | 重写OnInvocation方法 |
AspectBefore(抽象标签类) | 前置拦截器 | 重写Before方法 |
AspectAfter(抽象标签类) | 后置拦截器(不管目标方法成功失败都会执行) | 重写After方法 |
AspectAfterReturn(抽象标签类) | 后置拦截器(只有目标方法成功才会执行) | 重写AfterReturn方法 |
AspectAfterThrows(抽象标签类) | 错误拦截器(只有目标方法失败才会执行) | 重写AfterThrows方法 |
每个拦截器方法都有一个
名称 | 说明 |
---|---|
ComponentContext | DI容器,可以从中取得你已注册的实例 |
Arguments | 目标方法的参数 |
TargetMethod | 目标方法的MethodInfo |
ReturnValue | 目标方法的返回 |
Method | 目标方法的代理方法MethodInfo |
- 首先要自己写一个类继承 前置拦截器AspectBefore(抽象标签类)
- 实现该抽象类的Before方法
public class TestHelloBefore:AspectBefore
{
public override Task Before(AspectContext aspectContext)
{
Console.WriteLine("TestHelloBefore");
return Task.CompletedTask;
}
}
[Component]//Component注解里面有一个属性叫做InterceptorType默认为Class+virtual来实现代理包装
public class TestHello
{
[TestHelloBefore]//打上拦截器
public virtual void Say()
{
Console.WriteLine("Say");
}
}
前置拦截器方法的执行顺序为:先执行 TestHelloBefor的Before方法再执行你的Say方法
- 首先要自己写一个类继承后置拦截器AspectAfter(抽象标签类)
- 实现该抽象类的After方法
public class TestHelloAfter:AspectAfter
{
//这个 returnValue 如果目标方法正常返回的话 那就是目标方法的返回值
// 如果目标方法抛异常的话 那就是异常本身
public override Task After(AspectContext aspectContext,object returnValue)
{
Console.WriteLine("TestHelloAfter");
return Task.CompletedTask;
}
}
[Component]//Component注解里面有一个属性叫做InterceptorType默认为Class+virtual来实现代理包装
public class TestHello
{
[TestHelloAfter]//打上拦截器
public virtual void Say()
{
Console.WriteLine("Say");
}
}
执行顺序为:先执行你的SayAfter方法再执行 TestHelloAfter的After方法
这里要特别注意的是 After 拦截器 是不管你的目标方法(SayAfter是成功还是抛异常) 都被会执行到的
- 首先要自己写一个类继承拦截器AspectReturn(抽象标签类)
- 实现该抽象类的After方法
public class TestHelloAfterReturn:AspectAfterReturn
{
//result 是目标方法的返回 (如果目标方法是void 则为null)
public override Task AfterReturn(AspectContext aspectContext, object result)
{
Console.WriteLine("TestHelloAfterReturn");
return Task.CompletedTask;
}
}
[Component]//Component注解里面有一个属性叫做InterceptorType默认为Class+virtual来实现代理包装
public class TestHello
{
[TestHelloAfterReturn]//打上拦截器
public virtual void Say()
{
Console.WriteLine("Say");
}
}
执行顺序为:先执行你的Say方法再执行 TestHelloAfterReturn的AfterReturn方法
如果你的Say方法抛出异常那么就不会执行TestHelloAfterReturn的AfterReturn方法
- 首先要自己写一个类继承拦截器AspectReturn(抽象标签类)
- 实现该抽象类的After方法
public class TestHelloAfterThrows:AspectAfterThrows
{
public override Task AfterThrows(AspectContext aspectContext, Exception exception)
{
Console.WriteLine(exception.Message);
return Task.CompletedTask;
}
}
[Component]//Component注解里面有一个属性叫做InterceptorType默认为Class+virtual来实现代理包装
public class TestHello
{
[TestHelloAfterThrows]//打上拦截器
public virtual void Say()
{
Console.WriteLine("Say");
throw new ArgumentException("exception");
}
}
执行顺序为:先执行你的Say方法再执行 TestHelloAfterThrows的AfterThrows方法
如果你的Say方法不抛出异常那么就不会执行 TestHelloAfterThrows的AfterThrows方法
注意:OnInvocation方法除了AspectContext参数以外 还有一个 AspectDelegate _next 参数, 需要在你的Around拦截器方法显示调用 _next(aspectContext) 方法,否则目标方法不会被调用
- 首先要自己写一个类继承拦截器AspectArround(抽象标签类)
- 实现该抽象类的OnInvocation方法
public class TestHelloAround:AspectArround
{
public override async Task OnInvocation(AspectContext aspectContext, AspectDelegate _next)
{
Console.WriteLine("around start");
await _next(aspectContext);
Console.WriteLine("around end");
}
}
[Component]//Component注解里面有一个属性叫做InterceptorType默认为Class+virtual来实现代理包装
public class TestHello
{
[TestHelloAround]//打上拦截器
public virtual void Say()
{
Console.WriteLine("Say");
}
}
方法的执行顺序为:
- 先执行TestHelloAround的OnInvocation方法
- 然后TestHelloAround的OnInvocation方法里面执行的 await _next(aspectContext); 就会执行被拦截方法TestHello的Say方法;
[Component]//Component注解里面有一个属性叫做InterceptorType默认为Class+virtual来实现代理包装
public class TestHello
{
[TestHelloAround,TestHelloBefore,TestHelloAfter,TestHelloAfterReturn,TestHelloAfterThrows]//打上拦截器
public virtual void Say()
{
Console.WriteLine("Say");
}
}
代码的执行顺序为:
- 先执行TestHelloAround,打印 “around start” 然后执行到里面的_next(aspectContext)会触发下面
- 执行TestHelloBefore 打印 “TestHelloBefore”
- 执行目标方法 打印 "Say"
- 打印 “around end” TestHelloAround运行结束
- 执行TestHelloAfter 打印 “TestHelloAfter”
- 因为是目标方法成功执行 TestHelloAfterReturn 打印 “TestHelloAfterReturn”
由于是目标方法成功返回 没有异常,所以不会走进TestHelloAfterThrows
[Component]//Component注解里面有一个属性叫做InterceptorType默认为Class+virtual来实现代理包装
public class TestHello
{
[TestHelloAround,TestHelloBefore,TestHelloAfter,TestHelloAfterReturn,TestHelloAfterThrows]
public virtual void Say()
{
Console.WriteLine("Say");
throw new ArgumentException("exception");
}
}
代码的执行顺序为:
- 先执行TestHelloAround,打印 “around start” 然后执行到里面的_next(aspectContext)会触发下面
- 执行TestHelloBefore 打印 “TestHelloBefore”
- 执行目标方法 打印 "Say"
- 打印 “around end” TestHelloAround运行结束
- 执行TestHelloAfter 打印 “TestHelloAfter”
- 因为是目标方法异常 执行 TestHelloAfterThrows 打印异常信息
public class TestHelloBefore1:AspectBefore
{
public override Task Before(AspectContext aspectContext)
{
Console.WriteLine("TestHelloBefore1");
return Task.CompletedTask;
}
}
public class TestHelloAfter1:AspectAfter
{
//这个 returnValue 如果目标方法正常返回的话 那就是目标方法的返回值
// 如果目标方法抛异常的话 那就是异常本身
public override Task After(AspectContext aspectContext,object returnValue)
{
Console.WriteLine("TestHelloAfter1");
return Task.CompletedTask;
}
}
public class TestHelloAfterReturn1:AspectAfterReturn
{
//result 是目标方法的返回 (如果目标方法是void 则为null)
public override Task AfterReturn(AspectContext aspectContext, object result)
{
Console.WriteLine("TestHelloAfterReturn1");
return Task.CompletedTask;
}
}
public class TestHelloAround1:AspectArround
{
public override async Task OnInvocation(AspectContext aspectContext, AspectDelegate _next)
{
Console.WriteLine("TestHelloAround1 start");
await _next(aspectContext);
Console.WriteLine("TestHelloAround1 end");
}
}
public class TestHelloAfterThrows1:AspectAfterThrows
{
public override Task AfterThrows(AspectContext aspectContext, Exception exception)
{
Console.WriteLine("TestHelloAfterThrows1");
return Task.CompletedTask;
}
}
//////////////////////////////////////////////
public class TestHelloBefore2:AspectBefore
{
public override Task Before(AspectContext aspectContext)
{
Console.WriteLine("TestHelloBefore2");
return Task.CompletedTask;
}
}
public class TestHelloAfter2:AspectAfter
{
//这个 returnValue 如果目标方法正常返回的话 那就是目标方法的返回值
// 如果目标方法抛异常的话 那就是异常本身
public override Task After(AspectContext aspectContext,object returnValue)
{
Console.WriteLine("TestHelloAfter2");
return Task.CompletedTask;
}
}
public class TestHelloAfterReturn2:AspectAfterReturn
{
//result 是目标方法的返回 (如果目标方法是void 则为null)
public override Task AfterReturn(AspectContext aspectContext, object result)
{
Console.WriteLine("TestHelloAfterReturn2");
return Task.CompletedTask;
}
}
public class TestHelloAround2:AspectArround
{
public override async Task OnInvocation(AspectContext aspectContext, AspectDelegate _next)
{
Console.WriteLine("TestHelloAround2 start");
await _next(aspectContext);
Console.WriteLine("TestHelloAround2 end");
}
}
public class TestHelloAfterThrows2:AspectAfterThrows
{
public override Task AfterThrows(AspectContext aspectContext, Exception exception)
{
Console.WriteLine("TestHelloAfterThrows2");
return Task.CompletedTask;
}
}
[Component]
public class TestHello
{
[
TestHelloAround1(GroupName = "Aspect1",OrderIndex = 10),
TestHelloBefore1(GroupName = "Aspect1",OrderIndex = 10),
TestHelloAfter1(GroupName = "Aspect1",OrderIndex = 10),
TestHelloAfterReturn1(GroupName = "Aspect1",OrderIndex = 10),
TestHelloAfterThrows1(GroupName = "Aspect1",OrderIndex = 10)
]
[
TestHelloAround2(GroupName = "Aspect2",OrderIndex = 1),
TestHelloBefore2(GroupName = "Aspect2",OrderIndex = 1),
TestHelloAfter2(GroupName = "Aspect2",OrderIndex = 1),
TestHelloAfterReturn2(GroupName = "Aspect2",OrderIndex = 1),
TestHelloAfterThrows2(GroupName = "Aspect2",OrderIndex = 1)
]
public virtual void SayGroup()
{
Console.WriteLine("SayGroup");
}
}
如上面的代码在目标方法上打了2组 那么对应的执行顺序是:
- 先执行TestHelloAround2 打印 "TestHelloAround2 start" 然后执行到里面的_next(aspectContext)会触发下面
- 执行TestHelloBefore2 打印 “TestHelloBefore2” 然后进入到
- 执行TestHelloAround1 打印 “TestHelloAround1 start” 然后执行到里面的 _next(aspectContext)会触发下面
- 执行TestHelloBefore1 打印 “TestHelloBefore1”
- 执行目标方法 SayGroup 打印 "SayGroup"
- TestHelloAround1运行结束 打印 “TestHelloAround1 end”
- 执行 TestHelloAfter1 打印 “TestHelloAfter1”
- 执行 TestHelloAfterReturn1 打印 “TestHelloAfterReturn1”
- TestHelloAround2运行结束 打印 “TestHelloAround2 end”
- 执行 TestHelloAfter2 打印 “TestHelloAfter2”
- 执行 TestHelloAfterReturn2 打印 “TestHelloAfterReturn2”
执行的顺序如下图
public class TestHelloBefore:AspectBefore
{
public override Task Before(AspectContext aspectContext)
{
Console.WriteLine("TestHelloBefore");
return Task.CompletedTask;
}
}
public interface IHello
{
[TestHelloBefore]//打上拦截器 也会生效,注意看下面的文字说明
void SayHello();
}
public abstract class TestParentHello
{
[TestHelloBefore]//打上拦截器 也会生效
public virtual void Say()
{
Console.WriteLine("Say");
}
}
[Component]
public class TestHello:TestParentHello,IHello
{
public void SayHello()
{
}
}
本文介绍的拦截器标签的方式实现切面编程,是基于组件Castle创建代理类来实现的, 默认是采用继承原来的class,然后把virtual的方法进行重写,如果你原来的class有继承一些接口的话,代理类也会继承,并且aop也会生效, 只不过需要显示接口的方式调用才行 如下图:
public interface InterIgnoreAop
{
[ExceptionAop1Attribute]
[ExceptionAop2Attribute]
void sayIgnore();
}
[Component]
public class IgnoreAop1 : InterIgnoreAop
{
// 如果不用[IgnoreAop]注解的话 会走2个aop逻辑:ExceptionAop1Attribute 和 ExceptionAop2Attribute
[IgnoreAop] // 针对方法关闭AOP,那么2个aop逻辑都不会走了
// [IgnoreAop(Target = new[] { typeof(ExceptionAop1Attribute) })] // 针对方法关闭某个AOP,就只会走ExceptionAop2Attribute
public virtual void sayIgnore()
{
}
}