.NET Core利用動(dòng)態(tài)代理實(shí)現(xiàn)AOP(面向切面編程)
1.介紹
1.1 動(dòng)態(tài)代理作用
用動(dòng)態(tài)代理可以做AOP(面向切面編程),進(jìn)行無(wú)入侵式實(shí)現(xiàn)自己的擴(kuò)展業(yè)務(wù),調(diào)用者和被調(diào)用者之間的解耦,提高代碼的靈活性和可擴(kuò)展性,比如:日志記錄、性能統(tǒng)計(jì)、安全控制、事務(wù)處理、異常處理等等。本方式實(shí)現(xiàn)思路用的.NET Core原生的DispatchProxy類,再加《特性標(biāo)記》+《Handle接口》達(dá)到無(wú)入侵式擴(kuò)展 ,有興趣的朋友,自行改進(jìn)一下,封裝成組件。
有什么做的不好的或者建議,希望大家及時(shí)提出,幫助改進(jìn)。
代碼上傳在gitee:https://gitee.com/luoxiangbao/dynamic-proxy.git
1.2 原生DispatchProxy類介紹
DispatchProxy我去看了一下源碼,和我設(shè)想的差不多,就是Emit類庫(kù)直接編寫IL語(yǔ)言,動(dòng)態(tài)生成類和方法,然后在方法里調(diào)用Invoke方法,這個(gè)時(shí)候就我們只需要重寫Invoke方法,具體實(shí)現(xiàn)由我們自己管控。其性能很高,幾乎和我們寫好的C#編譯成IL沒多大區(qū)別,大家用的Autofac的AOP,我也看了一下,底層用的是Castle.Core類庫(kù),而Castle.Core底層還是用的Emit方式實(shí)現(xiàn),只是思路不同。
便于理解我給大家貼一下源碼:
1.定義抽象DispatchProxy類的Invoke元數(shù)據(jù)
2.Emit類庫(kù)直接編寫IL語(yǔ)言,為代理類添加調(diào)用Invoke方法代碼
1.3簡(jiǎn)單介紹一下:IL代碼
IL是.NET框架中間語(yǔ)言(Intermediate Language),編譯器可以直接將源程序編譯為.exe或.dll文件,而CLR(公共語(yǔ)言運(yùn)行時(shí))執(zhí)行的是IL語(yǔ)言,不是C#高級(jí)編程語(yǔ)言,IL代碼是一種近似于指令式的代碼語(yǔ)言,與匯編語(yǔ)言比較相近,給大家做個(gè)案例對(duì)比一下。
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
有興趣的朋友自己也可以去實(shí)現(xiàn)。接下來(lái)進(jìn)入正題,我們?cè)趺蠢肈ispatchProxy自己造輪子?。。?/p>
2.實(shí)現(xiàn)
2.1 繼承DispatchProxy
核心類就是,DispatchProxy。這是.NET core 原生的。會(huì)幫我們創(chuàng)建一個(gè)代理類
internal class DynamicProxy<T> : DispatchProxy { public T? decorated { get; set; }//目標(biāo)類 public Action<object?[]?>? _afterAction { get; set; } // 動(dòng)作之后執(zhí)行 public Action<object?[]?, object>? _beforeAction { get; set; } // 動(dòng)作之前執(zhí)行 protected override object? Invoke(MethodInfo? targetMethod, object?[]? args) { Exception exception = null; AfterAction(args); object result = null; try { //調(diào)用實(shí)際目標(biāo)對(duì)象的方法 result = targetMethod?.Invoke(decorated, args); } catch (Exception ex) { exception = ex; } BeforeAction(args, result); //調(diào)用完執(zhí)行方法后的委托,如果有異常,拋出異常 if (exception != null) { throw exception; } return result; } /// <summary> /// 創(chuàng)建代理實(shí)例 /// </summary> /// <param name="decorated">代理的接口類型</param> /// <param name="afterAction">方法執(zhí)行前執(zhí)行的事件</param> /// <param name="beforeAction">方法執(zhí)行后執(zhí)行的事件</param> /// <returns></returns> public T Create(T decorated, Action<object?[]?> afterAction, Action<object?[]?, object> beforeAction) { object proxy = Create<T, DynamicProxy<T>>(); // 調(diào)用DispatchProxy 的Create 創(chuàng)建一個(gè)新的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($"執(zhí)行之前異常:{ex.Message},{ex.StackTrace}"); } } private void BeforeAction(object?[]? args, object? result) { try { _beforeAction.Invoke(args, result); } catch (Exception ex) { Console.WriteLine($"執(zhí)行之后異常:{ex.Message},{ex.StackTrace}"); } } }
2.2 定義handle接口
這個(gè)接口定義:執(zhí)行之前、執(zhí)行之后兩個(gè)方法。用來(lái)實(shí)現(xiàn)具體業(yè)務(wù)邏輯的處理
internal interface IInterceptor { /// <summary> /// 執(zhí)行之前 /// </summary> /// <param name="args">參數(shù)</param> void AfterAction(object?[]? args); /// <summary> /// 執(zhí)行之后 /// </summary> /// <param name="args">參數(shù)</param> /// <param name="result">結(jié)果</param> void BeforeAction(object?[]? args, object result); }
2.3 定義AOP特性
1.用來(lái)標(biāo)記類具體使用哪個(gè)handle的實(shí)現(xiàn)來(lái)處理業(yè)務(wù)。
2. 特性定義Type屬性決定創(chuàng)建代理類的時(shí)候,具體使用哪個(gè)handle實(shí)現(xiàn)
[AttributeUsage(AttributeTargets.Class)] internal class InterceptAttribut : Attribute { public Type Type { get; set; } public InterceptAttribut(Type type) { this.Type = type; } }
2.4 定義創(chuàng)建代理類的工廠
這里就是來(lái)組裝代理類與handle實(shí)現(xiàn)的地方。
internal class ProxyFactory { /// <summary> /// 創(chuàng)建代理實(shí)例 /// </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); //創(chuàng)建代理類 var proxy = new DynamicProxy<T>().Create(decorated, interceptor.AfterAction, interceptor.BeforeAction); return proxy; } }
1.拿到具體類,獲取Type,獲取我們上面定義的特性,通過(guò)特性的屬性,用來(lái)創(chuàng)建handle實(shí)例
2.ServiceHelp是我定義的一個(gè)來(lái)獲取實(shí)例化的容器幫助類。這個(gè)用.NET CORE 原始的IOC。大家可替換成autofac
3.創(chuàng)建化代理實(shí)例,把實(shí)例和handle實(shí)現(xiàn)的具體方法:AfterAction、BeforeAction傳入。用于代理類執(zhí)行的時(shí)候,進(jìn)行真正的調(diào)用
2.5 定義ServiceHelp
這里大家可自行發(fā)揮
public static class ServiceHelp { public static IServiceProvider? serviceProvider { get; set; } public static void BuildServiceProvider(IServiceCollection serviceCollection) { //構(gòu)建容器 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.測(cè)試
3.1 定義handle實(shí)現(xiàn)
internal class AOPTest : IInterceptor { public void AfterAction(object?[]? args) { Console.WriteLine($"AOP方法執(zhí)行之前,args:{args}"); throw new Exception("異常測(cè)試(異常,但依然不能影響程序執(zhí)行)"); } public void BeforeAction(object?[]? args, object result) { Console.WriteLine($"AOP方法執(zhí)行之后,args:{args},result:{result}"); } }
3.2 定義Service接口
internal interface ITestService { public int Add(int a, int b); }
3.3實(shí)現(xiàn)Service接口
定義實(shí)現(xiàn),并且在類上加上,AOP交給哪個(gè)handle
[InterceptAttribut(typeof(AOPTest))] internal class TestService : ITestService { public int Add(int a, int b) { Console.WriteLine($"正在執(zhí)行--》Add({a},)"); throw new Exception("方法執(zhí)行--》測(cè)試異常"); return a + b; } }
3.4 大功告成
1.創(chuàng)建容器,把我們自己的業(yè)務(wù)實(shí)現(xiàn)都注冊(cè)好
2.通過(guò)工廠進(jìn)行,動(dòng)態(tài)創(chuàng)建代理實(shí)例
// See https://aka.ms/new-console-template for more information using Infrastructure.DynamicProxy; using Microsoft.Extensions.DependencyInjection; Console.WriteLine("Hello, World!"); //容器注冊(cè) IServiceCollection serviceCollection = new ServiceCollection(); serviceCollection.AddTransient(typeof(AOPTest)); serviceCollection.AddTransient<ITestService, TestService>(); //構(gòu)建容器 ServiceHelp.BuildServiceProvider(serviceCollection); //用工廠獲取代理實(shí)例 var s = ProxyFactory.Create<ITestService>(); var sum = s.Add(1, 2); Console.WriteLine("執(zhí)行完畢=====>" + sum);
3.5 效果
4.Demo
大家可直接訪問(wèn)我的,gitee
https://gitee.com/luoxiangbao/dynamic-proxy.git
以上就是.NET Core利用動(dòng)態(tài)代理實(shí)現(xiàn)AOP(面向切面編程)的詳細(xì)內(nèi)容,更多關(guān)于.NET Core實(shí)現(xiàn)AOP的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!
相關(guān)文章
vs2017軟鏈接失效而導(dǎo)致無(wú)法進(jìn)入安裝界面的解決方法
這篇文章主要為大家詳細(xì)介紹了vs2017軟鏈接失效而導(dǎo)致無(wú)法進(jìn)入安裝界面的解決方法,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2018-09-09.net core如何利用ConcurrentTest組件對(duì)方法進(jìn)行壓力測(cè)試詳解
這篇文章主要給大家介紹了關(guān)于.net core如何利用ConcurrentTest組件對(duì)方法進(jìn)行壓力測(cè)試的相關(guān)資料,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面來(lái)一起看看吧2018-11-11asp.net Parameters.AddWithValue方法在SQL語(yǔ)句的 Where 字句中的用法
今天晚上看論壇,有人提問(wèn)說(shuō),Parameters.AddWithValue方法在有些情況下不好使2009-01-01ASP.NETWeb服務(wù)器驗(yàn)證控件如何使用
這篇文章主要介紹了ASP.NETWeb服務(wù)器驗(yàn)證控件如何使用,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2015-09-09幾種判斷asp.net中session過(guò)期方法的比較
幾種判斷asp.net中session過(guò)期方法的比較,需要的朋友可以參考一下2013-04-04ASP.NET簡(jiǎn)單實(shí)現(xiàn)注銷功能
這篇文章主要介紹了如何ASP.NET簡(jiǎn)單實(shí)現(xiàn)注銷功能的方法以及簡(jiǎn)單示例,有需要的小伙伴可以參考下。2015-07-07ASP.NET網(wǎng)頁(yè)打印(只打印相關(guān)內(nèi)容/自寫功能)
朋友要求在前段時(shí)間完成的新聞的網(wǎng)站上加上一個(gè)功能,就是在每篇新聞瀏覽的頁(yè)面, 加一個(gè)打印銨鈕。讓用戶一點(diǎn)打印,能把整篇文章打印2013-01-01