什么是AOP
AOP(Aspect Oriented Programming),即面向切面編程。眾所周知,OOP(面向對象編程)通過的是繼承、封裝和多態等概念來建立一種對象層次結構,用於模擬公共行為的一個集合。OOP從縱向上區分出一個個的類來,而AOP則從橫向上向對象中加入特定的代碼。AOP使OOP由原來的二維變為三維了,由平面變成立體了。
AOP采用"橫切"的技術,剖解開封裝的對象內部,將影響了多個類的公共行為封裝到一個可重用模塊。將那些與業務無關,卻為業務模塊所共同調用的邏輯或責任封裝起來,便於減少系統的重復代碼,降低模塊之間的耦合度,並有利於未來的可操作性和可維護性。
簡單來說講,動態地將代碼切入到類的指定方法、指定位置上的編程思想就是面向切面的編程。
那Spring AOP,AspectJ又是啥呢?
AOP是面向切面編程的思想,而Spring AOP是這種思想的技術實現!同樣AspecJ也實現了AOP思想。
如果你仔細閱讀源碼,你會發現SpringAOP居然包含AspectJ,這是因為Spring AOP借助了AspectJ的語法,但底層技術用的還是Spring自己的。
一個小例子幫助你理解AOP
剛剛接觸面向切面編程理解起來還是有些難度的,很難區分橫向和縱向的概念,看看下面這個例子
上面的小例子展示了一個被划分模塊的典型應用。
每個球星的核心功能都是上場打球,而這些球星都需要經紀人這種類似的輔助功能,幫助球星簽代言合同,照顧球星起居生活等等。
為什么說AOP是OOP的補充和完善呢?
如果僅僅為了重用通用的功能,OOP中繼承或委托也可以完成。但是如果整個應用中都使用相同的基類,繼承往往會導致一個脆弱的對象體系,難以修改維護。而使用委托則會需要委托對象進行復雜的調用。
而AOP提供了取代繼承和委托的另一種可選方案,而且更加清晰明了。在使用面向切面編程時,我們仍然需要在定義一個通用功能,但是可以通過聲明的方式定義這個功能以何種方式在何處應用,而不需要改變受影響的類。橫向關注點可以被模塊化為特殊的類,這些類被稱為切面。這樣做有兩個好處:每個關注點都集中於一個地方們不是分散在多處代碼中;
應用場景舉例
1、日志模塊
日志代碼往往橫向地散布在所有對象層次中,而與它對應的對象的核心功能毫無關系對於其他類型的代碼,如安全性、異常處理和透明的持續性也都是如此。
2、事務管理
調用方法前開啟事務, 調用方法后提交關閉事務。
AOP的優點
1、面向切面編程使得每個關注點都集中於一個地方而不是分散在多處代碼中,便於后期的統一維護管理。
2、服務模塊更簡潔,它們只包含主要關注點,而次要關注點的代碼被轉移到切面中了。
3、對原方法進行方法增強,且不影響原方法的正常使用。
4、使用簡單可插拔的配置,在實際邏輯執行之前、之后或周圍動態添加橫切關注點。
AOP的術語整理
1) 切面(Aspect)
切面是通知和切點的結合。通知和切點共同定義了切面的全部內容——它是什么,在何時和何處完成其功能。比如事務管理是一個切面,權限管理也是一個切面。
2) 通知(Advice)
通知定義了切面是什么以及何時使用。除了描述切面要完成的工作,通知還解決了何時執行這個工作的問題。
Spring切面可以應用5種類型的通知:
前置通知(Before):在目標方法被調用之前調用通知功能
后置通知(After):在目標方法完成之后調用通知,不關心方法的輸出是什么。是“返回通知”和“異常通知”的並集。
返回通知(After-returning):在目標方法成功執行之后調用通知
異常通知(After-throwing):在目標方法拋出異常后調用通知
環繞通知(Around)通知包裹了被通知的方法,可同時定義前置通知和后置通知。
3) 切點(Pointcut)
切點定義了在何處工作,也就是真正被切入的地方,也就是在哪個方法應用通知。切點的定義會匹配通知所有要織入的一個或多個連接點。我們通常使用明確的類和方法名稱,或是利用正則表達式定義所匹配的類和方法名稱來指定這些切點。
4)連接點(Join point)
連接點是在應用執行過程中能夠插入切面的一個點。這個點可以是調用方法時,拋出異常時,甚至修改一個字段時。切面代碼可以利用這些點插入到應用的正常流程之中,並添加新的行為。
5) 引入(Introduction)
引入讓一個切面可以聲明被通知的對象實現了任何他們沒有真正實現的額外接口,而且為這些對象提供接口的實現。
引入允許我們向現有的類添加新方法或屬性。這個新方法和實例變量就可以被引入到現有的類中,從而可以再無需修改這些現有的類的情況下,讓它們具有新的行為和狀態。
5) 織入(Weaving):織入是把切面應用到目標對象並創建新的代理對象的過程。切面在指定的連接點被織入到目標對象中。在目標對象的生命周期里有多個點可以織入。
-
編譯器:切面在目標類編譯時被織入。這種方式需要特殊的編譯器。
-
類加載期:切面在目標類被引入應用之前增強該目標類的字節碼。
-
運行期:切面在應用運行的某個時刻被織入。