海水正藍

          面朝大海,春暖花開
          posts - 145, comments - 29, trackbacks - 0, articles - 1
            BlogJava :: 首頁 :: 新隨筆 :: 聯系 :: 聚合  :: 管理

          1.上下文Context、面向切面編程AOP模型分析

          在本人的“.NET面向上下文、AOP架構模式(概述)” 一文中,我們大概了解了上下文如何輔助對象在運行時的管理。在很多時候我們急需在運行時能把對象控制在一定的邏輯范圍內,在必要的時候能讓他們體現出集中 化的概念,如人群、車輛、動物等等。而Context與AOP有著密切的聯系,Context表示邏輯抽象的范圍而AOP描述了在這個邏輯范圍內如何進行 控制。其實這兩者都是設計模式外的設計模式,與具體的技術實現無關。[王清培版權所有,轉載請給出署名]
          那么Context與AOP兩者在邏輯上是一個怎樣的概念呢?似乎只有圖才能最貼切的表達人的理解思路。下圖展現Context與AOP緊密合作的概念模型。
          Context圖:1

          對象在運行時被上下文管理,在上下文中可以很方便的獲取到所有的受管理的對象,這為后面的AOP做了鋪墊。只有Context啟動后AOP管理器的爪子才能伸進對象的運行時內部與AOP的連接點建立起通訊關系,才能真正的使對象能面向切面成功。
          在模型圖中,Context中心負責對所有Object進行管理,而Object體現出多面性屬性、多面性行為都將包括多面性的特點,通過與AOP管理器進行連接將控制對象的運行時行為。
          AOP圖:2

          通過合理的約定對象的AOP抽象接口,盡可能的最大化將控制權移動到客戶所實現的“面”中去。比如對某類方法的調用,可能需要盡可能的控制方法的所有執行權。所以對具體的抽象定義有很大的難度。
          在上圖中,我們通過AOP核心管理器與對象的“面”連接上,根據具體的“面”類型進行動態調用,比如屬性,可能需要在運行時根據業務環節進行呈現、動態綁 定等等,都可以通過AOP去實現。對于方法,可能在面向SOA的架構中需要記錄下當前客戶端的調用信息,還有一些獨特的業務認證等等。不同的“面”需要進 行邏輯抽象,這也符合面向對象的設計原則。很多時候我們需要先“約定”而不是盡可能的提供擴展的機制,擴展點越多系統的復雜程度就越大,相對也就難以控 制。

          2.上下文的實現

          對上下文、AOP模型我們大致分析了一下,通過模型圖也很形象的體現出上下文、AOP的主要的工作原理。下面我們來通過具體的分析來搭建物理的代碼模型。
          面向對象是對抽象的邏輯模型進行物理性的建模,能否真正的體現出模型,需要我們細心的分析才行。

          2.1上下文模型實現

          我們對上下文模型進行抽象實現為代碼模型。那么我們需要一個邏輯上代表上下文的對象,在這里我將它命名為ContextRuntime,上下文的生 命周期控制在Using()語句的代碼段中,那么ContextRuntime需要實現Idisposable接口,讓Using()語句能起作用。

          using (ContextModule.ContextRuntime.BeginContextRuntime())

          {   //上下文的生命周期

          }

          為什么要這樣設計上下文的生命周期呢,這樣設計是最為靈活的。在諸如很多微軟的內部上下文生命周期的入口也是這樣設計的,最經典的就是System.Transaction事務處理。

          當Using()代碼段結束后,我們需要釋放當前上下文實例,所以我們需要完成IDisposable接口的實現。

          void IDisposable.Dispose()

          {

          _currentContextRuntime = null;

          }

          _ currentContextRuntime表示上下文對象實例的全局私有對象。

          由于多線程應用框架的入口點不是我們所能控制的,所以在使用上下文模式的時候需要使用線程本地存儲解決線程不安全訪問的問題。

           [ThreadStatic]

          private staticContextRuntime _currentContextRuntime;

          我們看一下全部的ContextRuntime對象代碼:

          1. /*** 
          2.  * author:深度訓練 
          3.  * blog:http://wangqingpei557.blog.51cto.com/ 
          4.  * **/  
          5. using System;  
          6. using System.Collections.Generic;  
          7. using System.Text;  
          8.   
          9. namespace ContextModule  
          10. {  
          11.     /// <summary>  
          12.     /// 上下文運行時環境。  
          13.     /// 上下文邏輯運行時環境,環境中的功能都是可以通過附加進來的。  
          14.     /// </summary>  
          15.     public class ContextRuntime : IDisposable  
          16.     {  
          17.         #region IDisposable成員  
          18.         void IDisposable.Dispose()  
          19.         {  
          20.             _currentContextRuntime = null;  
          21.         }  
          22.         #endregion  
          23.   
          24.         protected ContextRuntime() { }  
          25.         private DateTime _initTime = DateTime.Now;  
          26.         /// <summary>  
          27.         /// 獲取運行時創建上下文的時間  
          28.         /// </summary>  
          29.         public virtual DateTime InitTime { get { return _initTime; } }  
          30.         private Dictionary<object, object> _runTimeResource = new Dictionary<object, object>();  
          31.         private ContextFilterHandlerMap _filterMap = new ContextFilterHandlerMap();  
          32.         /// <summary>  
          33.         /// 獲取上下文中的方法、類過濾器映射表  
          34.         /// </summary>  
          35.         public ContextFilterHandlerMap FilterMap { get { return _filterMap; } }  
          36.         private Guid _initPrimaryKey = Guid.NewGuid();  
          37.         /// <summary>  
          38.         /// 獲取運行時創建上下文的唯一標識  
          39.         /// </summary>  
          40.         public virtual Guid InitPrimaryKey { get { return _initPrimaryKey; } }  
          41.         /// <summary>  
          42.         /// 獲取上下文共享區域中的數據  
          43.         /// </summary>  
          44.         /// <param name="key">數據Key</param>  
          45.         /// <returns>object數據對象</returns>  
          46.         public virtual object GetValue(object key)  
          47.         {  
          48.             return _runTimeResource[key];  
          49.         }  
          50.         /// <summary>  
          51.         /// 設置上下文共享區域中的數據  
          52.         /// </summary>  
          53.         /// <param name="key">數據Key</param>  
          54.         /// <param name="value">要設置的數據對象</param>  
          55.         public virtual void SetValue(object key, object value)  
          56.         {  
          57.             _runTimeResource[key] = value;  
          58.         }  
          59.   
          60.         [ThreadStatic]  
          61.         private static ContextRuntime _currentContextRuntime;  
          62.         /// <summary>  
          63.         /// 獲取當前上下文運行時對象.  
          64.         /// </summary>  
          65.         public static ContextRuntime CurrentContextRuntime { get { return _currentContextRuntime; } }  
          66.         /// <summary>  
          67.         /// 開始運行時上下文  
          68.         /// </summary>  
          69.         /// <returns>ContextRuntime</returns>  
          70.         public static ContextRuntime BeginContextRuntime()  
          71.         {  
          72.             //可以通過配置文件配置上下文運行時環境的參數。這里只是實現簡單的模擬。  
          73.             _currentContextRuntime = new ContextRuntime();  
          74.             return _currentContextRuntime;  
          75.         }  
          76.     }  
          77. }  

          這里只為了實現基本的模型原型,不會涉及太多的功能。上下文主要是在當前線程中開啟,然后保持在靜態對象的多線程安全訪問,最后就是對象的穩定釋放。

          2.2上下文對象綁定實現

          有了上下文之后,如何才能使對象在運行時動態的綁定到上下文中來。這個需要在前期編碼的時候就確定對象是否要綁定到當前上下文以便進行管理。

          那么我們需要對客戶使用的對象進行一個抽象,讓所有需要綁定的對象實現我們高層定義的抽象。這里我將命名為ContextModuleBaseObject,由于需要向AOP提供對象的“面”的連接點,所以我們需要在運行時反射獲取到綁定對象的一些基本信息,如:屬性的“面”、行為的“面”、包括對象本身的“面”,這些面我們需要將其對應關系建立起來才能讓后面的AOP起作用。

          所以我們將ContextModuleBaseObject定義為泛型類,并且需要加上Class的約束。對于綁定的對象在運行時一旦進入上下文的生命周期管理,就需要靈活的表示為ContextRuntime對象,這樣設計符合上下文一視同仁的觀念,更便于ContextModuleBaseObject對象在運行期動態的使用上下文的內部存儲區域。[王清培版權所有,轉載請給出署名]

          這里我們需要將ContextModuleBaseObject 對象繼承自ContextRuntime對象。使用經典的裝飾者模式,讓ContextModuleBaseObject 對象使用ContextRuntime 行為。

          1. /*** 
          2.  * author:深度訓練 
          3.  * blog:http://wangqingpei557.blog.51cto.com/ 
          4.  * **/  
          5. using System;  
          6. using System.Collections.Generic;  
          7. using System.Text;  
          8. using System.Reflection;  
          9.   
          10. namespace ContextModule  
          11. {  
          12.     /// <summary>  
          13.     /// 上下綁定基類,強制派生類綁定到上下文。  
          14.     /// 邏輯上下文的策略構造都在這里進行。  
          15.     /// </summary>  
          16.     /// <typeparam name="T">受管理的上下文綁定對象類型,通常是ContextModuleBaseObject派生類。</typeparam>  
          17.     public class ContextModuleBaseObject<T> : ContextRuntime where T : class  
          18.     {  
          19.         /// <summary>  
          20.         /// 當前上下文綁定對象所綁定到的上下文物理對象實例。  
          21.         /// </summary>  
          22.         private ContextRuntime _contextRunTime;  
          23.   
          24.         public ContextModuleBaseObject()  
          25.         {  
          26.             if (typeof(T).GetCustomAttributes(typeof(ContextEveningBoundAttribute), false) != null)  
          27.             {  
          28.                 _IsEvening = true;  
          29.                 return;  
          30.             }  
          31.             //前期靜態綁定上下文  
          32.             if (ContextRuntime.CurrentContextRuntime == null)  
          33.                 throw new Exception("上下文環境未能初始化,請檢查您的代碼入口是否啟用了ContextRuntime對象。");  
          34.             _contextRunTime = ContextRuntime.CurrentContextRuntime;  
          35.             _InitContextHandler<T>();  
          36.         }  
          37.         /// <summary>  
          38.         /// 構造上下文的類過濾器、方法過濾器映射表。  
          39.         /// </summary>  
          40.         private void _InitContextHandler<ChildType>() where ChildType : class  
          41.         {  
          42.             //構造類過濾器  
          43.             ContextOperationBaseAttribute[] classattr =  
          44.                 typeof(ChildType).GetCustomAttributes(typeof(ContextOperationBaseAttribute), false) as ContextOperationBaseAttribute[];  
          45.             if (classattr.Length > 0)  
          46.             {  
          47.                 ContextOperationBaseAttribute joinoper = _JoinOperation(classattr);  
          48.                 _contextRunTime.FilterMap.MapOperation(typeof(T).FullName, joinoper);  
          49.             }  
          50.             //構造方法過濾器  
          51.             foreach (MethodInfo method in typeof(ChildType).GetMethods())  
          52.             {  
          53.                 ContextOperationBaseAttribute[] methodattr =  
          54.                     method.GetCustomAttributes(typeof(ContextOperationBaseAttribute), false) as ContextOperationBaseAttribute[];  
          55.                 if (methodattr.Length <= 0)  
          56.                     continue;  
          57.                 ContextOperationBaseAttribute joinoper = _JoinOperation(methodattr);  
          58.                 _contextRunTime.FilterMap.MapOperation(string.Format("{0}.{1}", method.DeclaringType.FullName, method.Name), joinoper);  
          59.             }  
          60.         }  
          61.         internal bool _IsEvening { get; set; }  
          62.         /// <summary>  
          63.         /// 后期動態綁定上下文。  
          64.         /// </summary>  
          65.         internal void _EveningBoundChildClass<ChildType>() where ChildType : class  
          66.         {  
          67.             if (_contextRunTime != null)  
          68.                 return;//說明之前已經進行過動態調用  
          69.             _contextRunTime = ContextRuntime.CurrentContextRuntime;//動態綁定當前運行時上下文  
          70.             _InitContextHandler<ChildType>();  
          71.         }  
          72.   
          73.         private ContextOperationBaseAttribute _JoinOperation(ContextOperationBaseAttribute[] operationarray)  
          74.         {  
          75.             //必須對數組進行排序后才能連接  
          76.             for (int i = 0; i < operationarray.Length; i++)  
          77.             {  
          78.                 for (int j = 0; j < i; j++)  
          79.                 {  
          80.                     if (operationarray[j].OperationSort > operationarray[j + 1].OperationSort)  
          81.                     {  
          82.                         ContextOperationBaseAttribute oper = operationarray[j];  
          83.                         operationarray[j] = operationarray[j + 1];  
          84.                         operationarray[j + 1] = oper;  
          85.                     }  
          86.                 }  
          87.             }  
          88.             ContextOperationBaseAttribute opernext = operationarray[0];  
          89.             for (int i = 1; i < operationarray.Length; i++)  
          90.             {  
          91.                 opernext.NextOperation = operationarray[i];  
          92.                 opernext = operationarray[i];//保持對當前循環對象的上級對象的引用。  
          93.             }  
          94.             return operationarray[0];  
          95.         }  
          96.   
          97.         public MethodInfo GetMethodInfo(string methodname)  
          98.         {  
          99.             return this.GetType().GetMethod(methodname);  
          100.         }  
          101.         public override Guid InitPrimaryKey  
          102.         {  
          103.             get  
          104.             {  
          105.                 return _contextRunTime.InitPrimaryKey;  
          106.             }  
          107.         }  
          108.         public override DateTime InitTime  
          109.         {  
          110.             get  
          111.             {  
          112.                 return _contextRunTime.InitTime;  
          113.             }  
          114.         }  
          115.         public override object GetValue(object key)  
          116.         {  
          117.             return _contextRunTime.GetValue(key);  
          118.         }  
          119.         public override void SetValue(object key, object value)  
          120.         {  
          121.             _contextRunTime.SetValue(key, value);  
          122.         }  
          123.     }  
          124. }  

          ContextModuleBaseObject 類主要實現的功能就是將對象動態的添加到當前上下文中。然后為AOP做些輔助性的工作,包括對類、屬性、行為的特性元數據的緩存,這里只實現了行為的特性 緩存。可以根據自己的需要擴展AOP的功能,在對象的屬性上標記特性讓屬性也發揮作用。這里的特性就是AOP公布的指定接口。

          對_JoinOperation方法的解釋我們留在后面,這里是一個數據結構。將ContextOperationBaseAttribute

          類型串成鏈表,讓方法的執行穿過所有的ContextOperationBaseAttribute處理類。

          2.3上下文對象的后期綁定實現

          為了讓綁定對象支持上下文后期綁定,需要一個特性作為表示。

          1. /*** 
          2.  * author:深度訓練 
          3.  * blog:http://wangqingpei557.blog.51cto.com/ 
          4.  * **/  
          5. using System;  
          6. using System.Collections.Generic;  
          7. using System.Text;  
          8.   
          9. namespace ContextModule  
          10. {  
          11.     /// <summary>  
          12.     /// 確定設置類是否需要后期動態綁定到上下文。  
          13.     /// 使用該特性的類將是上下文活躍的,只有在使用的時候才確定當前上下文。  
          14.     /// </summary>  
          15.     [AttributeUsage(AttributeTargets.Class, AllowMultiple = false, Inherited = true)]  
          16.     public class ContextEveningBoundAttribute : Attribute  
          17.     {  
          18.         public ContextEveningBoundAttribute() { }  
          19.         private bool _isEvening;  
          20.         /// <summary>  
          21.         /// 指定對象是否需要后期動態綁定上下文。  
          22.         /// </summary>  
          23.         public bool IsEvening { set { _isEvening = value; } get { return _isEvening; } }  
          24.     }  
          25. }  

          僅僅為了標識后期綁定說明。在ContextModuleBaseObject 對象的構造函數中可以看到。

          1. public ContextModuleBaseObject()  
          2.         {  
          3.             if (typeof(T).GetCustomAttributes(typeof(ContextEveningBoundAttribute), false) != null)  
          4.             {  
          5.                 _IsEvening = true;  
          6.                 return;  
          7.             }  
          8.             //前期靜態綁定上下文  
          9.             if (ContextRuntime.CurrentContextRuntime == null)  
          10.                 throw new Exception("上下文環境未能初始化,請檢查您的代碼入口是否啟用了ContextRuntime對象。");  
          11.             _contextRunTime = ContextRuntime.CurrentContextRuntime;  
          12.             _InitContextHandler<T>();  
          13.         }  

          到這里我們已經實現對象的動態綁定到上下文來,下面我們來分析Context如何用AOP配合完成面向切面編程的機制。

           

          2.4.AOP中的對象行為的契約設計實現

          其實這里的契約設計也就是圖2中對AOP中的“面”的約定。

          AOP全稱為“面向切面編程”。對象在運行時具備多個面,其實 在.NET里面我們習慣性的用特性(Attribute)來表達這個概念。因為不需要改動任何代碼就可以將特性加到對象中的任何元素中去,在不同的業務環 節或者說是功能環節就能動態的轉動元素體現出“切面”的優勢,當然具體的實現可能很多種,這里使用特性來完成。

          在此約定任何處理對象方法的“面”都將被抽象。這里我將命名為ContextOperationBaseAttribute該特性表示所有附加到方法上的特性的基類,對“面”的抽象。

          那么不同類型的面將有著不同的操作行為,比如:記錄日志的特性、計算性能的特性、認證安全的特性他們都有著不同的行為和屬性,所以這里我們還需要提取一個頂層接口作為行為類的特性處理抽象。這里我將命名為IContextOperationHandler該接口作為統一執行行為特性的高層依賴。其實這里也體現出依賴倒置原則,依賴抽象不依賴具體實現。

          完整的ContextOperationBaseAttribute 類:

          1. /*** 
          2.  * author:深度訓練 
          3.  * blog:http://wangqingpei557.blog.51cto.com/ 
          4.  * **/  
          5. using System;  
          6. using System.Collections.Generic;  
          7. using System.Text;  
          8.   
          9. namespace ContextModule  
          10. {  
          11.     /// <summary>  
          12.     /// 上下文操作動作特性化基類。  
          13.     /// 所有對上下文中的類、方法的過濾操作都必須繼承此類。  
          14.     /// </summary>  
          15.     public abstract class ContextOperationBaseAttribute : Attribute, IContextOperationHandler  
          16.     {  
          17.         /// <summary>  
          18.         /// 過濾器的處理順序,從小到大的方式進行處理。  
          19.         /// </summary>  
          20.         public int OperationSort { get; set; }  
          21.         /// <summary>  
          22.         /// 下一次過濾操作類  
          23.         /// </summary>  
          24.         internal ContextOperationBaseAttribute NextOperation { get; set; }  
          25.         /// <summary>  
          26.         /// 開始處理過濾對象  
          27.         /// </summary>  
          28.         /// <typeparam name="Result">方法的返回值類型</typeparam>  
          29.         /// <param name="actionmethod">調用的方法包裝</param>  
          30.         /// <param name="paramarray">方法的有序參數</param>  
          31.         /// <returns></returns>  
          32.         public virtual Result ResultAction<Result>(ContextMethodInfo actionmethod, params object[] paramarray)  
          33.         {  
          34.             object result = null;  
          35.             if (!actionmethod.IsPost)  
          36.             {  
          37.                 result = (this as IContextOperationHandler).Operation(actionmethod, paramarray);  
          38.                 if (this.NextOperation != null)  
          39.                     return this.NextOperation.ResultAction<Result>(actionmethod, paramarray);  
          40.             }  
          41.             if (result != null)  
          42.                 return (Result)result;  
          43.             return default(Result);  
          44.         }  
          45.   
          46.   
          47.         public abstract object Operation(ContextMethodInfo contextmethod, params object[] paramarray);  
          48.     }  
          49. }  

          作為抽象的頂層類需要完成派生類重復的勞動。這里實現了一個ResultAction泛型方法,該方法是外部調用綁定對象的方法時的入口點。但是具體的實現區別在于IContextOperationHandler 接口的定義。

          由于行為的特性可能存在多個,所以對于最后一個處理完的特性需要結束整個的調用鏈表,并且返回值。在ResultAction虛方法里面對IContextOperationHandler 接口的Operation方法執行調用,該方法將會在實現特定行為特性里面實現,這里又體現出“模板方法”設計模式。在抽象類中約定行為,在派生類中實現具體。

          這里比較有意思的是,特性不在像大家實現ORM的那中簡單的標識了。其實特性真正強大的地方在于運行時能動態的獲取到,這得益于.NET元數據的功勞。并且動態實例化然后當作普通的對象實例使用。這個觀念很多.NET程序員不宜轉變。

          在這里的ContextOperationBaseAttribute 又描述了另外一種數據結構“單向鏈表”,為了將綁定對象的行為最大化的在特性中實現,我們將方法的調用完全的傳遞到實現特性中去。那么對方法上多個作用的 特性如何穿過呢,并且能保證數據的正常傳遞和返回。有兩點我們需要注意,一個是特性的作用順序,二個是特性對方法的執行是否完成。這兩點我們都要考慮進 去,所以在ContextOperationBaseAttribute 類中用public int OperationSort { get; set; }屬性表示特性的執行順序,記錄日志的特性和計算性能的特性我們很難在這里定死,需要根據后期程序的執行情況而定,如我要先記錄日志然后在執行方法。

          那么我們又如何將ContextOperationBaseAttribute類型串聯起來呢?在ContextModuleBaseObject

          泛型綁定類中我們在構造的時候就將通過ContextOperationBaseAttribute.OperationSort 屬性初始化了特性處理鏈表。

          那么我們如何將具體的對象與特性關聯建立起對應關系呢?一個行為可能有多個ContextOperationBaseAttribute的實現。所以這里我們需要一個能滿足行為與特性之間的數據結構。

          這里我將它定義為ContextFilterHandlerMap該類繼承自Dictionary<string,ContextOperationBaseAttribute>泛型字典類,使用KEY—VALUE的方式存放行為與ContextOperationBaseAttribute處理特性的對應關系。

          1. /*** 
          2.  * author:深度訓練 
          3.  * blog:http://wangqingpei557.blog.51cto.com/ 
          4.  * **/  
          5. using System;  
          6. using System.Collections.Generic;  
          7. using System.Text;  
          8.   
          9. namespace ContextModule  
          10. {  
          11.     /// <summary>  
          12.     /// 特定于上下文的過濾器映射表。  
          13.     /// 上下文中的任何方法如果需要進行上下文管理的,則使用ContextModule.ContextOperationBaseAttribute特性派生類進行管理。  
          14.     /// 所有附加于方法、類上的特性管理類都將被映射到ContextModule.ContextFilterHandlerMap實例中。  
          15.     /// </summary>  
          16.     public class ContextFilterHandlerMap : Dictionary<string, ContextOperationBaseAttribute>  
          17.     {  
          18.         public ContextFilterHandlerMap() { }  
          19.         /// <summary>  
          20.         /// 獲取方法對應的過濾器處理特性  
          21.         /// </summary>  
          22.         /// <param name="mapname">映射Key</param>  
          23.         /// <returns>ContextOperationBaseAttribute特性實例</returns>  
          24.         public ContextOperationBaseAttribute MapOperation(string mapname)  
          25.         {  
          26.             return this[mapname];  
          27.         }  
          28.         /// <summary>  
          29.         /// 設置過濾器與特定方法的映射  
          30.         /// </summary>  
          31.         /// <param name="mapname">映射Key</param>  
          32.         /// <param name="operationlist">過濾器特性基類ContextOperationBaseAttribute</param>  
          33.         public void MapOperation(string mapname, ContextOperationBaseAttribute operationlist)  
          34.         {  
          35.             this.Add(mapname, operationlist);  
          36.         }  
          37.     }  
          38. }  

          最后只需要向外提供IContextOperationHandler 接口就可以實現方法與處理特性的串聯了。

          1. /*** 
          2.  * author:深度訓練 
          3.  * blog:http://wangqingpei557.blog.51cto.com/ 
          4.  * **/  
          5. using System;  
          6. using System.Collections.Generic;  
          7. using System.Text;  
          8. using System.IO;  
          9.   
          10. namespace ContextModule  
          11. {  
          12.     /// <summary>  
          13.     /// 上下文操作管理接口  
          14.     /// </summary>  
          15.     public interface IContextOperationHandler  
          16.     {  
          17.         /// <summary>  
          18.         /// 開始上下文處理  
          19.         /// </summary>  
          20.         /// <param name="contextmethod">CRL目前正在執行的上下文方法的信息。  
          21.         /// 可以通過ContextMethodInfo實例獲取方法詳細信息。</param>  
          22.         ///<param name="paramarray">參數數組</param>  
          23.         object Operation(ContextMethodInfo contextmethod, params object[] paramarray);  
          24.     }  
          25. }  

          通過對外公開接口,讓實現“面”的客戶端去完成對具體對象方法的執行。ContextMethodInfo 類型是包裝System.Reflection. MethodInfo方法元數據的,將通過調用切入到方法內部。

          這里基本上實現了AOP對行為的多面支持,下面我們來看一下如果動態的切入到方法中。

          2.5.動態入口的實現

          對所有方法的調用將是比較頭疼的。由于一般面向上下文、面向切面都是有編寫者控制對方法的調用,可以很方便的通過后臺的隱式的調用。但是作為普通的方法的入口調用主要有三種方式實現。

          1):委托實現入口

          通過使用System.Delegate動態派生類型來完成對方法的調用,但是委托對于方法的簽名必須是強類型的,所以很難做到通用的調用入口。

          2):反射實現入口(通過擴展方法在OBJECT基類中加入獲取MethodInfo對象的方法,使用時通過該方法獲取調用方法的信息)

          通過擴展方法在System.Object中加入一個擴展方法用來獲取調用方法的信息,然后通過反射動態的調用,這種方法只比較常用的。但是如何框架是在.NET2.0中使用的擴展方法還不能實現,這里我是在ContextModuleBaseObject基類中加了一個類似擴展方法的方式。綁定對象可以很方便的獲取到調用方法的MethodInfo對象。

          3):完美的動態編譯(向抽象、多態敬禮)

          最為完美的是擴展代碼生成提供程序,在使用的對象里面在派生一個類,專門用來進行多態的轉移,讓高層的調用順利進入到派生的類中。不過比較復雜。

          這里是使用第二種方式使用的:

          1. /*** 
          2.  * author:深度訓練 
          3.  * blog:http://wangqingpei557.blog.51cto.com/ 
          4.  * **/  
          5. using System;  
          6. using System.Collections.Generic;  
          7. using System.Text;  
          8. using System.Reflection;  
          9.   
          10. namespace ContextModule  
          11. {  
          12.     /// <summary>  
          13.     /// 面向上下文的操作類。  
          14.     /// 對上下文發起的方法調用需要通過該基類進行調用才能讓我們的擴展點使用成為可能。  
          15.     /// </summary>  
          16.     public static class ContextAction  
          17.     {  
          18.         /// <summary>  
          19.         /// 在面向上下文的環境中進行方法的調用。  
          20.         /// </summary>  
          21.         /// <typeparam name="PostObjectType">調用的上下文綁定對象類型</typeparam>  
          22.         /// <typeparam name="ResultType">方法的返回類型</typeparam>  
          23.         /// <param name="post">調用的上下文綁定對象的實例</param>  
          24.         /// <param name="method">方法的信息對象MethodInfo,通過Oject.GetContextMethodInfo方法自動獲取。</param>  
          25.         /// <param name="paramarray">方法的有序參數集合</param>  
          26.         /// <returns>ResultType泛型類型指定的返回實例</returns>  
          27.         public static ResultType PostMethod<PostObjectType, ResultType>(PostObjectType post, MethodInfo method, params object[] paramarray)  
          28.             where PostObjectType : ContextModuleBaseObject<PostObjectType>  
          29.         {  
          30.             _LockPostObejctIsEveningBound<PostObjectType>(post);  
          31.             string key = string.Format("{0}.{1}", method.DeclaringType.FullName, method.Name);  
          32.             if (!ContextRuntime.CurrentContextRuntime.FilterMap.ContainsKey(key))  
          33.             {  
          34.                 throw new Exception(string.Format("方法{0}未經過上下文進行管理。", key));  
          35.             }  
          36.             ContextMethodInfo contextmethod = new ContextMethodInfo(method, post);  
          37.             return ContextRuntime.CurrentContextRuntime.FilterMap[key].ResultAction<ResultType>(contextmethod, paramarray);  
          38.         }  
          39.         /// <summary>  
          40.         /// 檢查調用實例類是否屬于后期綁定。  
          41.         /// 通過使用ContextModule.ContextEveningBound(IsEvening = true)方式指定后期綁定上下文。  
          42.         /// </summary>  
          43.         private static void _LockPostObejctIsEveningBound<PostObjectType>(PostObjectType post)  
          44.             where PostObjectType : ContextModuleBaseObject<PostObjectType>  
          45.         {  
          46.             ContextModuleBaseObject<PostObjectType> contextclass = post as ContextModuleBaseObject<PostObjectType>;  
          47.             if (contextclass._IsEvening)  
          48.                 contextclass._EveningBoundChildClass<PostObjectType>();  
          49.         }  
          50.     }  
          51. }  

          所有的調用均使用PostMethod泛型方法啟動。_LockPostObejctIsEveningBound私有方法,判斷當前類型是否是后期綁定,如果是則需要切入到基類中調用_ EveningBoundChildClass方法進行ContextOperationBaseAttribute 類型的鏈表構造,然后直接通過頭對象進行調用。

           

          3.實例上下文與靜態上下文

          對于實例上下文同時也就存在靜態上下文的概念,對于靜態對象的邏輯歸 納有點難度,由于靜態對象在面向對象設計方面很難抽象。只能通過特性注入的方式強制性的將靜態對象拉入上下文。但是在多線程的情況下,確實是可以研究的。 將靜態對象全部進行線程本地存儲,強制性的進行類似實體對象的管理。

          4.面向上下文的領域模型(DMM

          基于上下文的使用模式可以進行領域模型的初步構造,可以先向領域中的大比例結構靠近,將業務模型邏輯歸納到一定的Context中,對業務的模塊化梳理也是一種實現。[王清培版權所有,轉載請給出署名]

          在分層架構中的業務邏輯層可能需要加入上下文的管理,將業務模型進行運行時控制。比如訂單處理,將訂單業務流程相關的模型對象歸納為一塊。比如用戶相關,將用戶管理的業務流程相關的模型對象歸納為一塊,確實是很有意思。

          源碼地址:http://download.csdn.net/detail/wangqingpei557/4484912


          評論

          # re: 【轉】.NET面向上下文、AOP架構模式(實現)   回復  更多評論   

          2016-07-06 20:24 by SADFAS
          POIS[FISDPOIF[PIOWEPORIEW

          只有注冊用戶登錄后才能發表評論。


          網站導航:
           
          主站蜘蛛池模板: 辰溪县| 广州市| 西充县| 全椒县| 万年县| 安泽县| 丹巴县| 辽宁省| 汝城县| 武宣县| 景东| 承德市| 进贤县| 湘潭市| 黑山县| 景谷| 奇台县| 岚皋县| 岐山县| 湘潭市| 佳木斯市| 喀喇沁旗| 锡林郭勒盟| 南宁市| 缙云县| 元江| 鄱阳县| 黑水县| 清水河县| 喜德县| 龙江县| 黄冈市| 贺兰县| 寻乌县| 中方县| 万盛区| 白朗县| 志丹县| 合水县| 女性| 喀喇沁旗|