海水正藍

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

          日歷

          <2012年9月>
          2627282930311
          2345678
          9101112131415
          16171819202122
          23242526272829
          30123456

          文章檔案

          搜索

          •  

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

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

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

          通過合理的約定對象的AOP抽象接口,盡可能的最大化將控制權(quán)移動到客戶所實現(xiàn)的“面”中去。比如對某類方法的調(diào)用,可能需要盡可能的控制方法的所有執(zhí)行權(quán)。所以對具體的抽象定義有很大的難度。
          在上圖中,我們通過AOP核心管理器與對象的“面”連接上,根據(jù)具體的“面”類型進行動態(tài)調(diào)用,比如屬性,可能需要在運行時根據(jù)業(yè)務(wù)環(huán)節(jié)進行呈現(xiàn)、動態(tài)綁 定等等,都可以通過AOP去實現(xiàn)。對于方法,可能在面向SOA的架構(gòu)中需要記錄下當(dāng)前客戶端的調(diào)用信息,還有一些獨特的業(yè)務(wù)認證等等。不同的“面”需要進 行邏輯抽象,這也符合面向?qū)ο蟮脑O(shè)計原則。很多時候我們需要先“約定”而不是盡可能的提供擴展的機制,擴展點越多系統(tǒng)的復(fù)雜程度就越大,相對也就難以控 制。

          2.上下文的實現(xiàn)

          對上下文、AOP模型我們大致分析了一下,通過模型圖也很形象的體現(xiàn)出上下文、AOP的主要的工作原理。下面我們來通過具體的分析來搭建物理的代碼模型。
          面向?qū)ο笫菍Τ橄蟮倪壿嬆P瓦M行物理性的建模,能否真正的體現(xiàn)出模型,需要我們細心的分析才行。

          2.1上下文模型實現(xiàn)

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

          using (ContextModule.ContextRuntime.BeginContextRuntime())

          {   //上下文的生命周期

          }

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

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

          void IDisposable.Dispose()

          {

          _currentContextRuntime = null;

          }

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

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

           [ThreadStatic]

          private staticContextRuntime _currentContextRuntime;

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

          1. /*** 
          2.  * author:深度訓(xùn)練 
          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.     /// 上下文運行時環(huán)境。  
          13.     /// 上下文邏輯運行時環(huán)境,環(huán)境中的功能都是可以通過附加進來的。  
          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.         /// 獲取運行時創(chuàng)建上下文的時間  
          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.         /// 獲取運行時創(chuàng)建上下文的唯一標(biāo)識  
          39.         /// </summary>  
          40.         public virtual Guid InitPrimaryKey { get { return _initPrimaryKey; } }  
          41.         /// <summary>  
          42.         /// 獲取上下文共享區(qū)域中的數(shù)據(jù)  
          43.         /// </summary>  
          44.         /// <param name="key">數(shù)據(jù)Key</param>  
          45.         /// <returns>object數(shù)據(jù)對象</returns>  
          46.         public virtual object GetValue(object key)  
          47.         {  
          48.             return _runTimeResource[key];  
          49.         }  
          50.         /// <summary>  
          51.         /// 設(shè)置上下文共享區(qū)域中的數(shù)據(jù)  
          52.         /// </summary>  
          53.         /// <param name="key">數(shù)據(jù)Key</param>  
          54.         /// <param name="value">要設(shè)置的數(shù)據(jù)對象</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.         /// 獲取當(dāng)前上下文運行時對象.  
          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.             //可以通過配置文件配置上下文運行時環(huán)境的參數(shù)。這里只是實現(xiàn)簡單的模擬。  
          73.             _currentContextRuntime = new ContextRuntime();  
          74.             return _currentContextRuntime;  
          75.         }  
          76.     }  
          77. }  

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

          2.2上下文對象綁定實現(xiàn)

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

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

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

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

          1. /*** 
          2.  * author:深度訓(xùn)練 
          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.     /// 邏輯上下文的策略構(gòu)造都在這里進行。  
          15.     /// </summary>  
          16.     /// <typeparam name="T">受管理的上下文綁定對象類型,通常是ContextModuleBaseObject派生類。</typeparam>  
          17.     public class ContextModuleBaseObject<T> : ContextRuntime where T : class  
          18.     {  
          19.         /// <summary>  
          20.         /// 當(dāng)前上下文綁定對象所綁定到的上下文物理對象實例。  
          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.             //前期靜態(tài)綁定上下文  
          32.             if (ContextRuntime.CurrentContextRuntime == null)  
          33.                 throw new Exception("上下文環(huán)境未能初始化,請檢查您的代碼入口是否啟用了ContextRuntime對象。");  
          34.             _contextRunTime = ContextRuntime.CurrentContextRuntime;  
          35.             _InitContextHandler<T>();  
          36.         }  
          37.         /// <summary>  
          38.         /// 構(gòu)造上下文的類過濾器、方法過濾器映射表。  
          39.         /// </summary>  
          40.         private void _InitContextHandler<ChildType>() where ChildType : class  
          41.         {  
          42.             //構(gòu)造類過濾器  
          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.             //構(gòu)造方法過濾器  
          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.         /// 后期動態(tài)綁定上下文。  
          64.         /// </summary>  
          65.         internal void _EveningBoundChildClass<ChildType>() where ChildType : class  
          66.         {  
          67.             if (_contextRunTime != null)  
          68.                 return;//說明之前已經(jīng)進行過動態(tài)調(diào)用  
          69.             _contextRunTime = ContextRuntime.CurrentContextRuntime;//動態(tài)綁定當(dāng)前運行時上下文  
          70.             _InitContextHandler<ChildType>();  
          71.         }  
          72.   
          73.         private ContextOperationBaseAttribute _JoinOperation(ContextOperationBaseAttribute[] operationarray)  
          74.         {  
          75.             //必須對數(shù)組進行排序后才能連接  
          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];//保持對當(dāng)前循環(huán)對象的上級對象的引用。  
          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 類主要實現(xiàn)的功能就是將對象動態(tài)的添加到當(dāng)前上下文中。然后為AOP做些輔助性的工作,包括對類、屬性、行為的特性元數(shù)據(jù)的緩存,這里只實現(xiàn)了行為的特性 緩存。可以根據(jù)自己的需要擴展AOP的功能,在對象的屬性上標(biāo)記特性讓屬性也發(fā)揮作用。這里的特性就是AOP公布的指定接口。

          對_JoinOperation方法的解釋我們留在后面,這里是一個數(shù)據(jù)結(jié)構(gòu)。將ContextOperationBaseAttribute

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

          2.3上下文對象的后期綁定實現(xiàn)

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

          1. /*** 
          2.  * author:深度訓(xùn)練 
          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.     /// 確定設(shè)置類是否需要后期動態(tài)綁定到上下文。  
          13.     /// 使用該特性的類將是上下文活躍的,只有在使用的時候才確定當(dāng)前上下文。  
          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.         /// 指定對象是否需要后期動態(tài)綁定上下文。  
          22.         /// </summary>  
          23.         public bool IsEvening { set { _isEvening = value; } get { return _isEvening; } }  
          24.     }  
          25. }  

          僅僅為了標(biāo)識后期綁定說明。在ContextModuleBaseObject 對象的構(gòu)造函數(shù)中可以看到。

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

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

           

          2.4.AOP中的對象行為的契約設(shè)計實現(xiàn)

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

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

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

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

          完整的ContextOperationBaseAttribute 類:

          1. /*** 
          2.  * author:深度訓(xùn)練 
          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">調(diào)用的方法包裝</param>  
          30.         /// <param name="paramarray">方法的有序參數(shù)</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. }  

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

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

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

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

          那么我們又如何將ContextOperationBaseAttribute類型串聯(lián)起來呢?在ContextModuleBaseObject

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

          那么我們?nèi)绾螌⒕唧w的對象與特性關(guān)聯(lián)建立起對應(yīng)關(guān)系呢?一個行為可能有多個ContextOperationBaseAttribute的實現(xiàn)。所以這里我們需要一個能滿足行為與特性之間的數(shù)據(jù)結(jié)構(gòu)。

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

          1. /*** 
          2.  * author:深度訓(xùn)練 
          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.         /// 獲取方法對應(yīng)的過濾器處理特性  
          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.         /// 設(shè)置過濾器與特定方法的映射  
          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 接口就可以實現(xiàn)方法與處理特性的串聯(lián)了。

          1. /*** 
          2.  * author:深度訓(xùn)練 
          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目前正在執(zhí)行的上下文方法的信息。  
          21.         /// 可以通過ContextMethodInfo實例獲取方法詳細信息。</param>  
          22.         ///<param name="paramarray">參數(shù)數(shù)組</param>  
          23.         object Operation(ContextMethodInfo contextmethod, params object[] paramarray);  
          24.     }  
          25. }  

          通過對外公開接口,讓實現(xiàn)“面”的客戶端去完成對具體對象方法的執(zhí)行。ContextMethodInfo 類型是包裝System.Reflection. MethodInfo方法元數(shù)據(jù)的,將通過調(diào)用切入到方法內(nèi)部。

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

          2.5.動態(tài)入口的實現(xiàn)

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

          1):委托實現(xiàn)入口

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

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

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

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

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

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

          1. /*** 
          2.  * author:深度訓(xùn)練 
          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.     /// 對上下文發(fā)起的方法調(diào)用需要通過該基類進行調(diào)用才能讓我們的擴展點使用成為可能。  
          15.     /// </summary>  
          16.     public static class ContextAction  
          17.     {  
          18.         /// <summary>  
          19.         /// 在面向上下文的環(huán)境中進行方法的調(diào)用。  
          20.         /// </summary>  
          21.         /// <typeparam name="PostObjectType">調(diào)用的上下文綁定對象類型</typeparam>  
          22.         /// <typeparam name="ResultType">方法的返回類型</typeparam>  
          23.         /// <param name="post">調(diào)用的上下文綁定對象的實例</param>  
          24.         /// <param name="method">方法的信息對象MethodInfo,通過Oject.GetContextMethodInfo方法自動獲取。</param>  
          25.         /// <param name="paramarray">方法的有序參數(shù)集合</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}未經(jīng)過上下文進行管理。", key));  
          35.             }  
          36.             ContextMethodInfo contextmethod = new ContextMethodInfo(method, post);  
          37.             return ContextRuntime.CurrentContextRuntime.FilterMap[key].ResultAction<ResultType>(contextmethod, paramarray);  
          38.         }  
          39.         /// <summary>  
          40.         /// 檢查調(diào)用實例類是否屬于后期綁定。  
          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. }  

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

           

          3.實例上下文與靜態(tài)上下文

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

          4.面向上下文的領(lǐng)域模型(DMM

          基于上下文的使用模式可以進行領(lǐng)域模型的初步構(gòu)造,可以先向領(lǐng)域中的大比例結(jié)構(gòu)靠近,將業(yè)務(wù)模型邏輯歸納到一定的Context中,對業(yè)務(wù)的模塊化梳理也是一種實現(xiàn)。[王清培版權(quán)所有,轉(zhuǎn)載請給出署名]

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

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


          評論

          # re: 【轉(zhuǎn)】.NET面向上下文、AOP架構(gòu)模式(實現(xiàn))   回復(fù)  更多評論   

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

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


          網(wǎng)站導(dǎo)航:
           
          主站蜘蛛池模板: 抚州市| 涟水县| 报价| 连山| 彭州市| 郓城县| 奈曼旗| 毕节市| 连云港市| 六盘水市| 耿马| 安平县| 普陀区| 都昌县| 黑龙江省| 成武县| 溧水县| 班玛县| 贺兰县| 南川市| 千阳县| 宣恩县| 曲阜市| 北安市| 三河市| 南江县| 杂多县| 梅河口市| 大理市| 穆棱市| 雷州市| 绿春县| 五河县| 陕西省| 噶尔县| 甘德县| 华池县| 策勒县| 金川县| 普宁市| 阳东县|