Net 實現自定義Aop

陳顯達發表於2022-01-07

引言

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

 

相關文章