查看原文
其他

.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: nopIL_0001: ldstr "Hello World!"IL_0006: call void [System.Console]System.Console::WriteLine(string)IL_000b: nopIL_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 informationusing 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

出处:

https://www.cnblogs.com/Bob-luo/archive/2021/12/27/15716592.html

版权申明:本文来源于网友收集或网友提供,仅供学习交流之用,如果有侵权,请转告版主或者留言,本公众号立即删除。


支持小微:

腾讯云 双十二活动!玩服务器的可以搞搞,老客户也可以参加!

轻量服务器  2核4G8M80G 222元/3年  

爆款1核2G云服务器首年50元  

链接:https://curl.qcloud.com/bR8ycXZa


右下角,您点一下在看图片

小微工资涨1毛

商务合作QQ:185601686




您可能也对以下帖子感兴趣

文章有问题?点此查看未经处理的缓存