.NET Core利用动态代理实现AOP(面向切面编程)
1.介绍
1.1 动态代理作用
用动态代理可以做aop(面向切面编程),进行无入侵式实现自己的扩展业务,调用者和被调用者之间的解耦,提高代码的灵活性和可扩展性,比如:日志记录、性能统计、安全控制、事务处理、异常处理等等。本方式实现思路用的.net core原生的dispatchproxy类,再加《特性标记》+《handle接口》达到无入侵式扩展 ,有兴趣的朋友,自行改进一下,封装成组件。
有什么做的不好的或者建议,希望大家及时提出,帮助改进。
代码上传在gitee:https://gitee.com/luoxiangbao/dynamic-proxy.git
1.2 原生dispatchproxy类介绍
dispatchproxy我去看了一下源码,和我设想的差不多,就是emit类库直接编写il语言,动态生成类和方法,然后在方法里调用invoke方法,这个时候就我们只需要重写invoke方法,具体实现由我们自己管控。其性能很高,几乎和我们写好的c#编译成il没多大区别,大家用的autofac的aop,我也看了一下,底层用的是castle.core类库,而castle.core底层还是用的emit方式实现,只是思路不同。
便于理解我给大家贴一下源码:
1.定义抽象dispatchproxy类的invoke元数据
2.emit类库直接编写il语言,为代理类添加调用invoke方法代码
1.3简单介绍一下:il代码
il是.net框架中间语言(intermediate language),编译器可以直接将源程序编译为.exe或.dll文件,而clr(公共语言运行时)执行的是il语言,不是c#高级编程语言,il代码是一种近似于指令式的代码语言,与汇编语言比较相近,给大家做个案例对比一下。
c#代码:
class program { static void main(string[] args) { console.writeline("hello world!"); } }
il代码:
il_0000: nop il_0001: ldstr "hello world!" il_0006: call void [system.console]system.console::writeline(string) il_000b: nop il_000c: ret
有兴趣的朋友自己也可以去实现。接下来进入正题,我们怎么利用dispatchproxy自己造*!!!
2.实现
2.1 继承dispatchproxy
核心类就是,dispatchproxy。这是.net core 原生的。会帮我们创建一个代理类
internal class dynamicproxy<t> : dispatchproxy { public t? decorated { get; set; }//目标类 public action<object?[]?>? _afteraction { get; set; } // 动作之后执行 public action<object?[]?, object>? _beforeaction { get; set; } // 动作之前执行 protected override object? invoke(methodinfo? targetmethod, object?[]? args) { exception exception = null; afteraction(args); object result = null; try { //调用实际目标对象的方法 result = targetmethod?.invoke(decorated, args); } catch (exception ex) { exception = ex; } beforeaction(args, result); //调用完执行方法后的委托,如果有异常,抛出异常 if (exception != null) { throw exception; } return result; } /// <summary> /// 创建代理实例 /// </summary> /// <param name="decorated">代理的接口类型</param> /// <param name="afteraction">方法执行前执行的事件</param> /// <param name="beforeaction">方法执行后执行的事件</param> /// <returns></returns> public t create(t decorated, action<object?[]?> afteraction, action<object?[]?, object> beforeaction) { object proxy = create<t, dynamicproxy<t>>(); // 调用dispatchproxy 的create 创建一个新的t dynamicproxy<t> proxydecorator = (dynamicproxy<t>)proxy; proxydecorator.decorated = decorated; //把自定义的方法委托给代理类 proxydecorator._afteraction = afteraction; proxydecorator._beforeaction = beforeaction; return (t)proxy; } private void afteraction(object?[]? args) { try { _afteraction.invoke(args); } catch (exception ex) { console.writeline($"执行之前异常:{ex.message},{ex.stacktrace}"); } } private void beforeaction(object?[]? args, object? result) { try { _beforeaction.invoke(args, result); } catch (exception ex) { console.writeline($"执行之后异常:{ex.message},{ex.stacktrace}"); } } }
2.2 定义handle接口
这个接口定义:执行之前、执行之后两个方法。用来实现具体业务逻辑的处理
internal interface iinterceptor { /// <summary> /// 执行之前 /// </summary> /// <param name="args">参数</param> void afteraction(object?[]? args); /// <summary> /// 执行之后 /// </summary> /// <param name="args">参数</param> /// <param name="result">结果</param> void beforeaction(object?[]? args, object result); }
2.3 定义aop特性
1.用来标记类具体使用哪个handle的实现来处理业务。
2. 特性定义type属性决定创建代理类的时候,具体使用哪个handle实现
[attributeusage(attributetargets.class)] internal class interceptattribut : attribute { public type type { get; set; } public interceptattribut(type type) { this.type = type; } }
2.4 定义创建代理类的工厂
这里就是来组装代理类与handle实现的地方。
internal class proxyfactory { /// <summary> /// 创建代理实例 /// </summary> /// <param name="decorated">代理的接口类型</param> /// <returns></returns> public static t create<t>() { var decorated = servicehelp.getservice<t>(); var type = decorated.gettype(); var interceptattribut = type.getcustomattribute<interceptattribut>(); var interceptor = servicehelp.getservice<iinterceptor>(interceptattribut.type); //创建代理类 var proxy = new dynamicproxy<t>().create(decorated, interceptor.afteraction, interceptor.beforeaction); return proxy; } }
1.拿到具体类,获取type,获取我们上面定义的特性,通过特性的属性,用来创建handle实例
2.servicehelp是我定义的一个来获取实例化的容器帮助类。这个用.net core 原始的ioc。大家可替换成autofac
3.创建化代理实例,把实例和handle实现的具体方法:afteraction、beforeaction传入。用于代理类执行的时候,进行真正的调用
2.5 定义servicehelp
这里大家可自行发挥
public static class servicehelp { public static iserviceprovider? serviceprovider { get; set; } public static void buildserviceprovider(iservicecollection servicecollection) { //构建容器 serviceprovider = servicecollection.buildserviceprovider(); } public static t getservice<t>(type servicetype) { return (t)serviceprovider.getservice(servicetype); } public static t getservice<t>() { return serviceprovider.getservice<t>(); } }
3.测试
3.1 定义handle实现
internal class aoptest : iinterceptor { public void afteraction(object?[]? args) { console.writeline($"aop方法执行之前,args:{args}"); throw new exception("异常测试(异常,但依然不能影响程序执行)"); } public void beforeaction(object?[]? args, object result) { console.writeline($"aop方法执行之后,args:{args},result:{result}"); } }
3.2 定义service接口
internal interface itestservice { public int add(int a, int b); }
3.3实现service接口
定义实现,并且在类上加上,aop交给哪个handle
[interceptattribut(typeof(aoptest))] internal class testservice : itestservice { public int add(int a, int b) { console.writeline($"正在执行--》add({a},{b})"); throw new exception("方法执行--》测试异常"); return a + b; } }
3.4 大功告成
1.创建容器,把我们自己的业务实现都注册好
2.通过工厂进行,动态创建代理实例
// see https://aka.ms/new-console-template for more information using infrastructure.dynamicproxy; using microsoft.extensions.dependencyinjection; console.writeline("hello, world!"); //容器注册 iservicecollection servicecollection = new servicecollection(); servicecollection.addtransient(typeof(aoptest)); servicecollection.addtransient<itestservice, testservice>(); //构建容器 servicehelp.buildserviceprovider(servicecollection); //用工厂获取代理实例 var s = proxyfactory.create<itestservice>(); var sum = s.add(1, 2); console.writeline("执行完毕=====>" + sum);
3.5 效果
4.demo
大家可直接访问我的,gitee
https://gitee.com/luoxiangbao/dynamic-proxy.git
以上就是.net core利用动态代理实现aop(面向切面编程)的详细内容,更多关于.net core实现aop的资料请关注其它相关文章!
上一篇: 直接用锅吃