AOP概念

 

13.1 簡介

面向切面編程採用另外一種編程框架完成面向對象編程. 然而,面向對象是把應用程序分解成多層次的對象,而面向切面編程把應用程序分解成各個切面或者說關係面. 切面對關注點進行模塊化,例如橫切多個類型和對象的事務管理。 (這些關注點術語通常稱作橫切(crosscutting)關注點。)

Spring.net的一個關鍵的組件就是 AOP框架。 儘管如此,Spring.net IoC容器並不依賴於AOP,這意味着你可以自由選擇是否使用AOP,AOP提供強大的中間件解決方案,這使得Spring.net IoC容器更加完善。

 

Spring.NET中所使用的AOP:

* 提供聲明式企業服務,特別是爲了代替COM+聲明式企業式服務. 最重要的服務是 聲明性事務管理(declarative transaction management) ,這個服務建立在Spring.NET的抽象事務管理(transaction abstraction)之上。

* 允許用戶實現自定義的切面,用AOP來完善OOP的使用。

 

這樣你可以把Spring.NET AOP看作是一種允許Spring.NET提供聲明式事務管理而不必借用COM+的一種授權技術;或者可以充分發揮Spring.NET AOP框架來實現自定義切面.

 

 

13.1.1 AOP概念

       讓我們從定義幾個最主要的AOP概念開始這方面的內容. 以下這些術語不是Spring.NET技術專有的. 不幸的是,AOP術語並不是特別的直觀;如果Spring.NET使用自己的術語,將會問題變得更加令人困惑。

 

*切面(Aspect):一個關注點的模塊化,這個關注點可能會橫切多個對象。事務管理是企業級應用(.NET)中一個關於橫切關注點的很好的例子。在Spring.NET中,切面可以使用 Advisors 或者 interceptors來實現.

 

*連接點(Joinpoint): 在程序執行過程中某個特定的點,比如某方法調用的時候或者處理異常的時候。

 

*通知(Advice):在AOP框架中,通知發生在某些特殊的點上.通知有不同的類型,包括around,before,還有throws.關於通知的類型將會在下面討論. 許多AOP框架,包括Spring.NET,都是以interceptors(攔截器)做通知模型,並維護一個以連接點爲中心的攔截器鏈。

 

*切入點(Pointcut):匹配連接點(Joinpoint)的斷言。通知和一個切入點表達式關聯,並在滿足這個切入點的連接點上運行(例如,當執行某個特定名稱的方法時)。一個AOP框架必須允許開發者去詳細主義自己的切入點,例如,使用常量表達式.

 

*引入(Introduction):增加方法或者字段到一個類. Spring.NET允許你引入新的接口到任何詳細定義過的對象.例如,你可以使用引入讓所有的對象執行一個Iauditable接口,這樣就簡化了跟蹤一個對象狀態的變化情況.

 

*目標對象(Target Object):包含一個連接點的對象.也被稱爲代理對象.

 

*AOP代理(AOP Proxy):AOP框架產生的對象,包括通知(Advice).在Spring.NET中, AOP代理是一個使用IL代碼在運行時產生的動態代理.

 

*織入(Weaving):把切面(aspect)連接到其它的應用程序類型或者對象上,並創建一個被通知(advised)的對象。這些可以在編譯時(例如使用Gripper-Loom.NET編譯器),類加載時和運行時完成。Spring.NET在運行時織入.

 

不同類型的通知(Advice):

環繞通知(Around Advice):包圍一個連接點(join point)的通知,如方法調它也會選擇是否繼續執行連接點或直接返回它們自己的返回值或拋出異常來結束執行。用。這是最強大的一種通知類型。環繞通知可以在方法調用前後完成自定義的行爲。

 

前置通知(Before advice):在某連接點(join point)之前執行的通知,但這個通知不能阻止連接點前的執行(除非它拋出一個異常)。

拋出通知(Throws advice):當一個方法拋出異常時,這種類型的通知被執行. Spring.NET提供了強而有力的拋出通知,所以你可以編寫捕獲你所感興趣的異常的代碼,而不必從Exception這個超類轉化而來.

 

返回後通知(After returning advice):在某連接點(join point)正常完成後執行的通知:例如,一個方法沒有拋出任何異常,正常返回。

 

Spring.NET提供了所有類型的通知, 我們推薦你使用盡量簡單的通知類型來實現需要的功能。例如,如果你只是需要用一個方法的返回值來更新緩存,雖然使用環繞通知也能完成同樣的事情,但是你最好使用After returning通知而不是環繞通知。用最合適的通知類型可以使得編程模型變得簡單,並且能夠避免很多潛在的錯誤。 比如,你不需要調用 JoinPoint(用於Around Advice)的 proceed() 方法,就不會有調用的問題。

   切入點(pointcut)概念是AOP的關鍵,這使得能從其它老的僅僅能提供攔截功能技術區別出AOP. 切入點使得定位通知(advice)可獨立於OO層次。例如,一個提供聲明式事務管理的around通知可以被應用到一組橫跨多個對象中的方法上.因此切入點提供了AOP的結構化組件.

 

 

13.1.2 Spring.NET AOP的功能

       Spring.NET AOP用純C#實現.它不需要專門的編譯過程----所有的編入都會在運行時完成. Spring.NET AOP不需要控制或者修改裝載器的的加載方式,它也不需要依靠沒有完成的API,所以它適合在CLR環境中使用.

       Spring.NET目前僅支持方法調用攔截,還不支持字段攔截,但增加字段攔截也不會破壞Spring.NET AOP APIs的代碼.

       Spring.NET provides提供了表示切入點和各種通知的類. Spring.NET 爲一個表示切面的對象使用術語顧問 (advisor),包括一個通知和一個指向特定連接點的切入點.

       不同的通知類型是ImethodInterceptor(這個接口來自AOP聯盟的攔截API),而通知的所有接口定義在Spring.Aop名字空間裏.所有的通知必須實現AopAlliance.Aop.Iadvice標籤接口.通知支持它的包裝是IMethodInterceptor ; IThrowsAdvice; IBeforeAdvice; 還有 IAfterReturningAdvice..關於通知更詳細的內容我們將會在下面講到.

       Spring.NET還提供了一個由AOP 聯盟定義的JAVA接口的.NET轉換.環形通知必須實現AOP聯盟的AopAlliance.Interceptr.IMethodInterceptor接口.同時,在JAVA領域,也爲AOP 聯盟提供了廣泛的支持, Spring.NET目前只適用於利用這些接口的.NET AOP 框架.就目前來說,這將會爲同時在.NET和JAVA領域中搞開發的開發者提供一個協調的編程模型, 從更長遠的發展來看,我們當然希望看見更多的.NET 項目適應AOP聯盟(AOP Alliance)的接口.

       Spring.NET AOP從來沒有打算通過提供一種全面的AOP解決方案來取代AspectJ. 然而, Spring.NET爲許多順從於AOP 的.NET應用提供了一套優秀的解決方案.

       所有,看到Spring.NET AOP的功能跟Spring.NET IoC container一起協調使用你也不會再感到驚訝了.AOP用跟普通對象定義一樣的語法來詳細說明;通知和切入點由Spring.NET IoC實現自己的管理.

 

13.1.3 Spring.NET 的AOP代理

       Spring.NET使用系統的類在運行時產生代理. Reflection.Emit名字空間爲代理的類產生IL代碼.這樣就能產生很有效益的代理,並且這些代理不會對繼承的層次關係施加任何限制.

       另外一種常見的實現代理的方法是使用ContextBoundObject對象和.NET遠程架構作爲攔截機制.我們對使用ContextBoundObject這種方法不是很提倡,因爲它需要直接或者間接繼承於ContextBoundObject的類被當作代理.依我們看來,使你的類繼承於第三訪會使你的應用很難控制.而且這種機制產生的Context-bound代理也會比第一種方法產生的代理會由於上下文交換和遠程架構而速度慢很多.

       Spring.NET AOP代理也是很輕巧的----這是由於代理的配置在代理產生的時候已經知道了,產生的代理如果有必要的話能夠通過映射來調用目標方法而來優化自己(比如說,有通知應用於目標方法時).在其它的事例中,目標方法被直接地調用,這樣就避免了執行衝突.

       最後, Spring.NET AOP代理永遠不會返回一個沒有經過任何未知的引用給目標對象.無論何時,如果目標方法返回一個未知的引用給一個目標對象,AOP代理會馬上意識到發生了什麼事,並會用自己的引用來取代這個返回的未知的引用.

       目前,產生代理的實現方式使用了對象的組合來代表代理到目標對象的請求,這跟你怎樣實現一個Decorator模式很相似.這意味着要被作爲代理的類必須實現一個或者更多的接口,這種方法將會比使用ContextBoundObject方法更少的聚合要求.

 

 

 

 

 

 

 

 

13.2 Spring.NET AOP API

       讓我們看看Spring.NET怎樣操作切入點這個重要概念的.

13.2.1 概念

 

       Spring.NET的切入點模型使得切入點可以獨立於通知類型進行重用,這就使得針對不同通知( advice)使用相同的切入點(pointcut)成爲可能。

       Spring.Aop.Ipointcut是最核心的接口.用來將通知應用於特定的類和方法.這個接口的完整定義如下:

        public interface IPointcut 
         { 
          ITypeFilter TypeFilter { get; } 
           IMethodMatcher MethodMatcher { get; } 
         } 

IPointcut接口分割成有利於重用類型和方法匹配的兩部分, 以及進行更細粒度的操作組合(例如與另一個方法匹配實現進行“或操作”)。

       ItypeFilter接口用來將切入點限制在一個給定的類集合裏面. 如果matches()方法總是返回true,所有目標類都將被匹配:

       public interface ITypeFilter

{

           bool Matches(Type type);

}

 

       ImethodMatcher接口通常更重要,這個接口的完整定義如下:

       public interface IMethodMatcher

{

           bool IsRuntime { get; }

bool Matches(MethodInfo method, Type targetType);

bool Matches(MethodInfo method, Type targetType, object[] args);

}

       Matches(MethodInfo, Type)方法用來測試這個切入點是否匹配目標類的指定方法。這將在AOP代理被創建的時候執行,這樣可以避免在每次方法調用的時候都執行。如果兩個參數的matches方法對於一個給定的方法返回true並且IMethodMatcher接口的IsRuntime方法也返回true,那麼有三個參數的matches方法將在每個方法調用時被調用. 這使得切入點在通知將被執行前可以查看傳入到方法的參數。

       絕大多數的IMethodMatcher接口是static,這也就意味着它們的IsRuntime屬性返回false.在這種情況下,有三個參數的Matches方法將永遠不會被調用.

提示

應儘可能地使切入點是靜態的,這就允許AOP框架在AOP代理被創建時緩存對切入點的計算結果。

 

13.2.2 在切入點上的操作

       Spring.NET支持在切入點上的操作有:或和與

       * 或運算表示只需有一個切入點被匹配就執行方法。

* 與運算表示所有的切入點都匹配的情況下才執行。

* 通常或運算要更有用一些。

 

   切入點能使用Spring.Aop.Support.Pointcuts類中的的靜態方法來編寫,或者使用同一個包內的ComposablePointcut.

13.2.3 便利的切入點實現

       Spring.NET提供了一些很方便的切入點實現.一些是開箱即用的, 其它的是切入點應用規範的子集。

發佈了56 篇原創文章 · 獲贊 2 · 訪問量 6萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章