引言
何為AOP,在軟體開發中,總是聽到這個AOP這個詞語,但是何為AOP呢,AOP全稱是Aspect Oriented Programming,中文譯為面向切面程式設計,什麼意思呢,即我們的應用程式在執行的時候,我們在呼叫方法的時候,我們當前這個父類方法需要呼叫下面某個類的方法,等待這個方法給我們返回一個結果或者不返回,那這樣的過程我們可以抽象的理解為自上而下,然後在自下而上,那AOP的概念我們就可以理解為在這個自上而下,和自下而上的過程中我們,我們實現了一層攔截,橫插了一個處理程式,用來實現對方法和方法之間呼叫的一個攔截,可以實現自上而下,經過我們的AOP層面的程式碼,以及自下而上的時候 經過我們的AOP程式碼,在這個AOP層面,我們可以實現對程式的日誌記錄,異常處理,引數驗證等等的一些常規操作。
實現方式
Aop的實現方式,大體是分為兩個版本一個是不同框架下的實現方式,不同平臺就是Framework下面的實現方式,還有一種是Core下面的實現方式,這裡我們主要講這兩種,第二個實現方式下面是兩個通用的實現方式,一種是基於IL的形式去實現,還有一種是基於記憶體的形式的實現,這裡不太對這兩種進行過多的講解,後續會寫一個使用IL去實現AOP的程式碼,這裡主要講FrameWork和Core框架下如何實現AOP代理的兩種比較簡單的方法。
frameWork
在framework的框架下,可以使用RealProxy類來實現靜態代理的的aop,需要自己去繼承RealProxy這個類,然後實現Invoke的抽象方法,即可實現Aop的實現,接下來我們看程式碼,
public class DynamicProxy<T> : RealProxy { public T Instance = default; public IInterceptor Interceptor; public DynamicProxy():base(typeof(T)) { } public T GetInstance< Target, TInterceptor>() where TInterceptor: IInterceptor where Target: class,T { var result = this.GetTransparentProxy(); Instance = Activator.CreateInstance<Target>() ; Interceptor = Activator.CreateInstance<TInterceptor>(); return (T)result; } public override IMessage Invoke(IMessage msg) { var methodMsg = msg as IMethodCallMessage; try { if (methodMsg!=null) { var methodInfo = methodMsg.MethodBase as MethodInfo; if (Interceptor != null) { Interceptor.BeforeEvent(methodMsg.MethodBase, methodMsg.InArgs); } var result= methodMsg.MethodBase.Invoke(Instance, methodMsg.InArgs); if (Interceptor != null) { Interceptor.AfterEvent(methodMsg.MethodBase, result); } return new ReturnMessage(result, null, 0, methodMsg.LogicalCallContext, methodMsg); } } catch (Exception ex) { if (Interceptor != null) { Interceptor.ExceptionEvent(ex, methodMsg.MethodBase); } } return new ReturnMessage(null, null, 0, methodMsg.LogicalCallContext, methodMsg); } } public interface IBase { string GetName(); } public class BaseModel : IBase { public string GetName() { return Guid.NewGuid().ToString(); } }
使用方式
var proxy = new DynamicProxy<IBase>(); var ins=proxy.GetInstance<BaseModel,TestInterceptor>(); var result=ins.GetName();
我們在需要代理的物件的時候,我們傳入了這個物件的繼承的型別,在建構函式呼叫了RealProxy的構造方法傳入我們需要代理的型別Type,然後在這裡我寫了一個建立物件以及設定攔截器的一個方法,可以看到在這個方法裡,我們獲取到了這個泛型T的靜態代理的物件,這是我們要返回給上一層的,此處是我們建立的代理物件,在下面我們有建立了一個這個Target的物件,很多人就有些疑惑了,為什麼同一型別的物件我們需要建立兩次呢,這裡呢是因為,如果我們同意的去使用這個靜態的代理作為我們的Instance的話,那在Invoke方法裡,我們呼叫我們呼叫的GetName的方法的Invoke的時候,會造成一個死迴圈的一個操作,就是不停的去GetName,也就不停止的走我們重寫的Invoke的方法,這裡,就起到了一個隔離作用,簡單來說,就是上層物件需要將一個型別代理,走到我們的GetInstance方法中去,我們給他返回這個代理的物件,然後我們類內部同時有一個未被代理的物件在建立出來,這樣我們的類有一個沒被代理的例項,這樣在代理的物件呼叫GetName的時候就可以走到我們的Invoke的方法中去,我們在執行GetName的方法時候我們使用Instance例項去承載我們所呼叫的方法,獲取到結果之後在返回到呼叫的上方去,就類似於橋接的方式,我呼叫了A的GetName方法,但是在代理層面有一個B的例項,實際上我們是呼叫的是B的GetName的方法,而且GetInstance方法裡面的返回必須是代理的物件,不然是不會走到Invoke方法中去,從而沒辦法實現攔截。
可以看到我們在GetInstance的時候我們也建立了我們的攔截器的例項,再看我們的Invoke方法,我們在方法的執行前,執行後,以及異常的時候我們分別呼叫了攔截器的BeforeEvent,AfterEvent以及ExceptionEvent方法,分別去傳入我們的執行前後,異常等資訊。
Net Core
在net core框架出來之後呢,代理方面也是有了一個改動,在fw版本下可以使用RealProxy實現AOP的功能,但是由於其效能方面以及其他方面的原因,core並不支援RealProxy,以及Core是不支援fw版本中的Remoting的,所以Core是以另一種方式支援代理去實現AOP的功能,其效能以及使用起來大大簡化了RealProxy的功能,並且如果非面向抽象開發的前提下,RealProxy代理還需要繼承MarshalByRefObject這個抽象介面,導致代理的物件呼叫方法的時候,過於依賴MarshalByRefObject,.方法名稱的時候是可以看到基類的方法,這對我們來說很不友好,所以Core版本引入了DispatchProxy的類來實現代理,這個類同RealProxy一樣是個抽象類,也必須實現Invoke方法。
/// <summary> /// Aop Proxy /// </summary> public class DynamicProxy : DispatchProxy { /// <summary> /// 執行方法介面 /// </summary> private IInterceptor interceptor { get; set; } /// <summary> /// 具體型別 /// </summary> private object service { get; set; } /// <summary> /// 建立代理 /// </summary> /// <param name="targetType"></param> /// <param name="interceptor"></param> /// <param name="serviceParameter"></param> /// <returns></returns> public static object Create(Type targetType, IInterceptor interceptor, object[] serviceParameter = null) { object proxy = GetProxy(targetType); ((DynamicProxy)proxy).CreateInstance(interceptor); ((DynamicProxy)proxy).service = CreateServiceInstance(targetType, serviceParameter); return proxy; } /// <summary> /// 建立代理,targetType為類,interceptorType繼承IInterceptor,serviceParameter為targetType為類建構函式的引數,parameters為interceptorType建構函式引數 /// </summary> /// <param name="targetType"></param> /// <param name="interceptorType"></param> /// <param name="serviceParameter"></param> /// <param name="parameters"></param> /// <returns></returns> public static object Create(Type targetType, Type interceptorType, object[] serviceParameter = null, params object[] parameters) { object proxy = GetProxy(targetType); ((DynamicProxy)proxy).CreateInstance(interceptorType, parameters); ((DynamicProxy)proxy).service = CreateServiceInstance(targetType, serviceParameter); return proxy; } /// <summary> /// tIService為介面,tService實現tIService介面,intercer繼承IInterceptor,serviceParameter為targetType為類建構函式的引數,parameters為interceptorType建構函式引數 /// </summary> /// <param name="tIService"></param> /// <param name="tService"></param> /// <param name="intercer"></param> /// <param name="serviceParameter"></param> /// <param name="parameters"></param> /// <returns></returns> public static object Create(Type tIService, Type tService, Type intercer, object[] serviceParameter = null, params object[] parameters) { var proxy = GetProxy(tIService); ((DynamicProxy)proxy).CreateInstance(intercer, parameters); ((DynamicProxy)proxy).service = CreateServiceInstance(tService, serviceParameter); return proxy; } /// <summary> /// TTarget為介面,tService實現tIService介面,TInterceptor繼承IInterceptor,serviceParameter為targetType為類建構函式的引數,parameters為interceptorType建構函式引數 /// </summary> /// <typeparam name="TTarget"></typeparam> /// <typeparam name="TService"></typeparam> /// <typeparam name="TInterceptor"></typeparam> /// <param name="serviceParameter"></param> /// <param name="parameters"></param> /// <returns></returns> public static TTarget Create<TTarget, TService, TInterceptor>(object[] serviceParameter = null, params object[] parameters) where TInterceptor : IInterceptor where TService : TTarget { var proxy = GetProxy(typeof(TTarget)); ((DynamicProxy)proxy).CreateInstance(typeof(TInterceptor), parameters); ((DynamicProxy)proxy).service = CreateServiceInstance(typeof(TService), serviceParameter); return (TTarget)proxy; } /// <summary> /// 建立指定型別物件,servicePara建構函式引數 /// </summary> /// <param name="type"></param> /// <param name="servicePara"></param> /// <returns></returns> private static object CreateServiceInstance(Type type, params object[] servicePara) { return Activator.CreateInstance(type, servicePara); } /// <summary> /// 建立代理,表示式執行泛型方法效能優於MakeGenericMethod /// </summary> /// <param name="targetType"></param> /// <returns></returns> private static object GetProxy(Type targetType) { var callexp = Expression.Call(typeof(DispatchProxy), nameof(DispatchProxy.Create), new[] { targetType, typeof(DynamicProxy) }); return Expression.Lambda<Func<object>>(callexp).Compile().Invoke(); } /// <summary> /// 建立Aop具體實現類,表示式效能優於反射效能 /// </summary> /// <param name="interceptorType"></param> /// <param name="parameters"></param> private void CreateInstance(Type interceptorType, object[] parameters) { var ctorParams = parameters.Select(x => x.GetType()).ToArray(); var paramsExp = parameters.Select(x => Expression.Constant(x)); var newExp = Expression.New(interceptorType.GetConstructor(ctorParams), paramsExp); this.interceptor = Expression.Lambda<Func<IInterceptor>>(newExp).Compile()(); } /// <summary> /// 賦值 /// </summary> /// <param name="interceptor"></param> private void CreateInstance(IInterceptor interceptor) { this.interceptor = interceptor; } /// <summary> /// 實現Invole方法 /// </summary> /// <param name="method"></param> /// <param name="parameters"></param> /// <returns></returns> protected override object Invoke(MethodInfo method, object[] parameters) { if (method == null) throw new Exception("無效的方法"); try { if (this.interceptor != null) { this.interceptor.BeforeEvent(method, parameters); } object result = method.Invoke(service, parameters); if (method.ReturnType.BaseType == typeof(Task)) { var resultTask = result as Task; if (resultTask != null) { resultTask.ContinueWith(task => { if (task.Exception != null) { if (interceptor != null) { var resultEx = this.interceptor.ExceptionEvent(task.Exception.InnerException ?? task.Exception, method); result = resultEx; } } else { object taskResult = task.GetType().GetProperty("Result").GetValue(task); if (interceptor != null) { this.interceptor.AfterEvent(method, taskResult); } } }).ConfigureAwait(false).GetAwaiter().GetResult(); return result; } } else { try { if (interceptor != null) { this.interceptor.AfterEvent(method, result); return result; } } catch (Exception ex) { if (interceptor != null) { return this.interceptor.ExceptionEvent(ex, method); } else { return null; } } } return null; } catch (Exception ex) { if (interceptor != null) { return this.interceptor.ExceptionEvent(ex, method); } else { return null; } } } }
從Invoke方法來看,直接成了我們所需要呼叫的方法的資訊,以及對應的引數,那同樣的,這個類實際上也有一些缺陷就是,Dispatch這個類裡面有一個Create的方法可以去為我們生成代理類,但是這個Create方法,如果你傳入的Type是具體的class,Create方法是會報錯的,因為Create方法不支援具體的型別,而是對應的父類介面型別,至於抽象類,我沒試過,有興趣的小夥伴可以在後面自己試一下呼叫Create方法傳入的是抽象類的前提下是否可以代理成功。
同樣的,在RealProxy中我們可以記錄日誌,異常,執行前,執行後等操作,在這個Invoke裡面,我們同樣可以,這便是我在FrameWork以及Core中實現Aop的兩種方式。
IL的形式去實現
之前的部落格中,我有寫過IL方面的合集,那實際上通過使用IL我們也可以實現一個動態代理去實現AOP的功能,目前的話,我是沒有寫相關的程式碼,但是IL的話 大體思路是這樣的,我們去動態建立DLL以及Module,以及去建立一個Type繼承我們需要代理的類或者介面,然後我們需要去用IL去實現父類的那幾個方法,然後我們講我們建立的型別去返回給依賴方,依賴方在呼叫方法的時候,會進入到我們用IL寫的程式碼中去,在IL構造的方法中,我們可以直接return代理物件的同名同型別的方法,從而實現AOP的功能,可能在這裡說的比較抽象,後面我會寫一篇使用IL去實現AOP的功能程式碼,到時候會在部落格中一一講解。
記憶體的形式
實際上,記憶體的形式目前我是沒有寫過,但是在網上有看到過相關的程式碼,其是利用反射我們獲取到方法的MethodHandle然後通過記憶體的形式,然後通過記憶體Copy實現的AOP,相關程式碼目前我已找不到,因為這種方式需要的功力深厚,目前我是達不到的,如果後續研究明白,再來一一分析,分享給大家,針對於第四種這種實現方式,大家可以參考一下這個部落格https://www.cnblogs.com/Bob-wei/p/7345574.html,這種方式去實現AOP的手段,目前我是整不明白的。下一篇部落格的話,我可能會寫一些c#中跨程式通訊的各種手段。
RealProxy版本:http://121.43.235.192:8082/s/Sb5xs7rH88CECn6
DispatchProxy版本:http://121.43.235.192:8082/s/xpKFAWc6rpb7nd6
DispatchProxy版本中,我是實現了一個EFCore的一個讀寫分離,實現了讀寫分離的兩種方式的一個案例。
大家如果有不懂的地方,可以看如果自己加的net群裡有叫四川觀察的基本上就是我,或者可以直接新增群聊可以找到我,在此,謝謝各位大佬的支援,後續依舊會帶來更多的乾貨