Net 實現自定義Aop

引言

       何為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,相關程式碼目前我已找不到,因為這種方式需要的功力深厚,目前我是達不到的,如果後續研究明白,再來一一分析,分享給大家,下一篇部落格的話,我可能會寫一些c#中跨進程通訊的各種手段。

     RealProxy版本://121.43.235.192:8082/s/Sb5xs7rH88CECn6

     DispatchProxy版本://121.43.235.192:8082/s/xpKFAWc6rpb7nd6

     DispatchProxy版本中,我是實現了一個EFCore的一個讀寫分離,實現了讀寫分離的兩種方式的一個案例。

     大家如果有不懂的地方,可以看如果自己加的net群里有叫四川觀察的基本上就是我,或者可以直接添加群聊可以找到我,在此,謝謝各位大佬的支援,後續依舊會帶來更多的乾貨

 

Tags: