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),
C#程式碼:
IL程式碼:
有興趣的朋友自己也可以去實現。接下來進入正題,我們怎麼利用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($"方法執行之前,args:{args}"); } public void BeforeAction(object?[]? args, object result) { Console.WriteLine($"方法執行之後,args:{args},result:{result}"); throw new NotImplementedException(); } }
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) { 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);
4.Demo
大家可直接訪問我的,gitee
https://gitee.com/luoxiangbao/dynamic-proxy.git