Spring AOP(一)——基礎概念

前文的一些內容更多是針對Spring容器內部的一些特性的描述,接下來一個專題將描述Spring AOP的一些信息,配置細節等等。

介紹

面向切面編程(AOP)是一種新的針對程序結構的思路,它補足了面向對象編程(OOP)的一些細節上的不足。OOP的關鍵在於模塊化概念,也就是Java中的class。而AOP關心的模塊則是切面。切面關心的模塊化主要是考慮的是諸如事物管理這類會跨越多個類型和對象的一些方面。(而這些類型對象通常是在多個不同業務層的。)

Spring的其中一個核心組件也就是AOP框架。而Spring IoC容器並不依賴AOP,也就是說,開發者如果不想使用AOP,就可以不使用AOP,AOP以一種中間件的方式補足了Spring IoC的功能。

Spring 2.0 AOP
Spring 2.0引入了一種既簡單又有效的方式來支持定製切面,無論是使用基於契約(XML)的方式,還是基於@AspectJ註解的方式。兩種方式都是支持AOP的全部功能的。
之後的AOP系列會將針對兩種方式分別討論。Spring 2.0 AOP是完全兼容之前的Spring 1.2 AOP的。後續AOP系列也會討論AOP的相關API。

AOP在Spring框架中起的作用主要有兩點:

  • 提供顯式聲明的企業服務,尤其是用來替換EJB服務的情況。其中最重要的服務就是諸如事務管理之類的服務。
  • 允許用戶來實現定製的切面,使用AOP來補足OOP的不足。

AOP 基本概念

首先,我們來看下AOP的核心概念以及相關術語。這些術語並不是Spring特有的。很可惜的是,AOP的術語不是很直觀,尤其是在Spring使用它自己的術語的時候很令人疑惑。

  • Aspect:一個橫切多個類的模塊化的服務。事物管理就是一個很好的例子,在企業應用當中,他會跨越很多的模塊。在Spring的AOP中,切面是通過一般的類來實現(基於契約的方式)或者通過註解了@Aspect註解的一般類來實現(@AspectJ方式)。
  • JoinPoint:程序的一個執行點,比如一個方法的執行,或者是處理一個異常。在Spring AOP中,JoinPoint總是代表折方法的執行過程。
  • Advice:JoinPoint過程中的一些動作。包括aroundbefore以及after這幾種類型的Advide。很多的AOP框架,包括Spring,都會將Advide作爲一個interceptor(攔截器),保證在一個JoinPoint有一個攔截鏈。
  • Pointcut:判定是否匹配JoinPoint,Advide是和Pointcut表達式關聯的,只有在Pointcut匹配的時候,纔會運行在JoinPoint上面(舉例來說,匹配一個方法的名字)。JoinPoint的概念和Pointcut表達式匹配是AOP中最重要的概念,默認情況下,Spring使用AspectJ的Pointcut表達式語言。
  • Introduction:聲明額外的方法或者私有變量來代表一個類型。Spring AOP允許開發者來引入新的接口(以及對應的實現類)到切面對象上。舉例來說,開發者可以通過使用Introduction,令Bean來實現IsModified接口,來簡化緩存(Introduction作爲AspectJ中的內在聲明類型)。
  • TargetObject:由切面切入的對象就是TargetObject。也稱之爲advised對象。因爲Spring AOP是通過實時代理來實現的,這個對象將總是一個代理的對象。
  • AOP proxy:爲了實現切面約束而由AOP框架創建的對象就是AOP proxy。在Spring框架中,AOP的代理就是JDK動態代理或者CGLIB代理。
  • Weaving:和應用其他類型連接的切面,或者是創建的Advice對象的過程。這一過程可以在編譯期(使用AspectJ編譯器),加載期,或者運行時完成。Spring AOP和其它的純Java的AOP框架一樣,是在運行時執行Weaving過程的。

Advice的類型

  • Before Advice: 在JoinPoint執行之前執行的Advice,但是不能夠阻止JoinPoint的執行,除非拋出異常。
  • After Returning Advice:在JoinPoint正常完成的情況下執行的Advice,簡單來說,就是一個方法沒有拋出異常。
  • After Throwing Advice:在JoinPoint不正常完成的情況下執行的Advice,簡來單說,就是方法拋出異常的時候執行的Advice。
  • After(finally) Advice:無論一個JoinPoint執行正常還是非正常,都會執行的Advice。
  • Around Advice:以一層調用包裹了JoinPoint的Advice,這是最常見,最有效的一種Advice。Around Adivce可以執行定製的行爲,無論是在方法的執行之前還是執行之後。Around Advice也負責決定是否開始進入JoinPoint或者是執行方法其他方法來返回或者拋出異常。

Around Advice也是最泛化的一種Advice。但是Spring AOP中,像AspectJ都提供了很多不同類型的Advice,所以我們仍然建議開發者少使用Around Advice,而是使用最合適的Advice來實現特定的行爲。舉例來說,如果開發者只需要更新一個緩存來返回方法的值,那麼實現一個Returning Advice就比Around Advice更好,儘管Around Advice也能夠實現同樣的功能。使用更爲具體的Advice類型可以簡化變成的模型,去除一些潛在的錯誤。舉例來說,開發者在Around Advice上不需要在JoinPoint上調用proceed()方法,一旦調用就可能產生錯誤。

在Spring 2.0的版本中,所有的參數都是靜態的定義的,所以當開發者使用Advice的參數的時候,可以使用適當的類型而不是Object的數組。

JoinPoint的執行和PointCut的匹配概念,是AOP區別於老的的攔截技術的關鍵。PointCut使得Advice可以獨立於面向對象層次來執行。舉例來說,一個提供顯式的事務管理的Around Advice可以用於多個對象,跨越多個不同的服務層級而工作。

Spring AOP的能力和目的

Spring AOP是純Java實現的。不需要其他特殊的處理。Spring AOP也不需要控制類加載的層次,所以在應用服務器或者是Servlet容器中應用都很方便。

Spring AOP 當前只支持方法執行的JoinPoint(基於Spring Bean方法的Advice執行),實例變量的攔截是不支持的,儘管支持這個功能也不會破壞掉Spring AOP核心的API。如果開發者需要針對實例變量的訪問和更新JoinPoint的話,可以考慮使用AspectJ語言。

Spring AOP框架和其他的AOP框架細節上還是有些不同的。Spring的目的不是爲了支持最完整的AOP實現(儘管Spring AOP功能很完善),Spring AOP更多關心的是提供AOP和Spring IoC的集成,以便能夠解決企業級應用的常見問題。

比如,Spring框架的AOP功能通常都是結合Spring IoC容器來使用的。切面的配置,也基本都是使用Bean定義的語法(當然Spring AOP也支持強大的自動代理的能力),這就是和其它AOP實現的一個最大的不同。當然,使用Spring AOP也會有一些限制,比如Advice一些細粒度的對象(比如域對象之類的)很難:如果AOP面對的常見問題多數是這種情況的話,使用AspectJ可能是更好的選擇。當然,Spring團隊的經驗是,Spring AOP對絕大多數的企業應用場景,都是十分適用的。

Spring AOP不會努力去實現所有AspectJ的功能以提供完整的AOP解決方案。我們相信無論是基於代理的框架像Spring AOP或者是成熟的AOP框架,比如AspectJ都是十分有價值的,並且他們是相互補充的關係,而並非競爭的關係。Spring通過AspectJ無縫地集成了Spring AOP和IoC,使得所有基於Spring的應用架構能夠方便的集成AOP。這種集成不會影響Spring AOP的API或者AOP聯盟的API:Spring AOP仍然保持向後兼容。

Spring框架的核心原則之一就是non-invasiveness(輕量級),這一概念的意思就是開發者不必強制引入一些框架的類和接口到應用的業務層或者是模型層。當然,有的時候,Spring框架也支持開發者引入框架的特定依賴:之所以Spring提供這樣的支持,是因爲在某些場景下,使用Spring框架的特定類能更簡單的實現這些功能。Spring框架(幾乎)總會提供這樣的選擇。開發者可以自由選擇是否需要使用來最佳的貼合實際的應用場景。
開發者還可以根據自己的場景來使用不同的AOP框架。開發者使用AspectJ或者Spring AOP都是沒有問題的,亦或是使用@AspectJ註解的方式,或者是Spring XML配置的方式,都可以。本章更多介紹的是@AspectJ的方式,是因爲Spring團隊更偏好基於註解的方式。

AOP 代理

Spring AOP默認情況下是使用標準的JDK 動態代理來作爲AOP的代理的,它可以使得任何接口被代理。

Spring AOP也可以使用CGLIB代理。這種代理更多的是代理類,而不是接口。CGLIB默認情況下,是當一個業務對象沒有實現接口的時候,來代理的。當然,好的編程習慣肯定最好是基於接口的。業務類通常也會實現多個業務接口。當然,強制使用CGLIB作爲代理也是可以的。但是在那種情況下,開發者需要聲明方法爲並非實現接口的方法,或者需要傳遞一個代理對象到方法作爲具體的類型。

理解Spring AOP是基於代理實現的是非常重要的。在後續的文章中可以看到具體的例子。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章