引言
何為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群裡有叫四川觀察的基本上就是我,或者可以直接添加群聊可以找到我,在此,謝謝各位大佬的支援,後續依舊會帶來更多的幹貨