Spring AOP是什麼?你都拿它做什麼?

為什麼會有面向切面編程(AOP)?我們知道Java是一個面向對象(OOP)的語言,但它有一些弊端,比如當我們需要為多個不具有繼承關係的對象引入一個公共行為,例如日誌、權限驗證、事務等功能時,只能在在每個對象裡引用公共行為。這樣做不便於維護,而且有大量重複代碼。AOP的出現彌補了OOP的這點不足。

為了闡述清楚Spring AOP,我們從將以下方面進行討論:

  1. 代理模式
  2. 靜態代理原理及實踐
  3. 動態代理原理及實踐
  4. Spring AOP原理及實戰

1. 代理模式

代理模式:為其他對象提供一種代理以控制對這個對象的訪問。這段話比較官方,但我更傾向於用自己的語言理解:比如A對象要做一件事情,在沒有代理前,自己來做;在對 A 代理後,由 A 的代理類 B 來做。代理其實是在原實例前後加了一層處理,這也是 AOP 的初級輪廓。

2. 靜態代理原理及實踐

靜態代理模式:靜態代理說白了,就是在程序運行前就已經存在代理類的字節碼文件、代理類和原始類的關係在運行前就已經確定。廢話不多說,我們看一下代碼。為了方便閱讀,博主把單獨的 class 文件合併到接口中,讀者可以直接複製代碼運行:

Spring AOP是什麼?你都拿它做什麼?


測試結果:

Spring AOP是什麼?你都拿它做什麼?

靜態代理雖然保證了業務類只需關注邏輯本身,代理對象的一個接口只服務於一種類型的對象。如果要代理的方法很多,勢必要為每一種方法都進行代理。再者,如果增加一個方法,除了實現類需要實現這個方法外,所有的代理類也要實現此方法。增加了代碼的維護成本。那麼要如何解決呢?答案是使用動態代理。

3. 動態代理原理及實踐

動態代理模式:動態代理類的源碼是在程序運行期間,通過 JVM 反射等機制動態生成。代理類和委託類的關係是運行時才確定的。實例如下:

Spring AOP是什麼?你都拿它做什麼?


測試結果如下:

Spring AOP是什麼?你都拿它做什麼?

Spring AOP是什麼?你都拿它做什麼?


其實是 JDK 動態生成了一個類去實現接口,隱藏了這個過程:

Spring AOP是什麼?你都拿它做什麼?


使用 JDK 生成的動態代理的前提是目標類必須有實現的接口。但這裡又引入一個問題,如果某個類沒有實現接口,就不能使用 JDK 動態代理。所以 CGLIB 代理就是解決這個問題的。

CGLIB 是以動態生成的子類繼承目標的方式實現,在運行期動態的在內存中構建一個子類,如下:

Spring AOP是什麼?你都拿它做什麼?


CGLIB 使用的前提是目標類不能為 final 修飾。因為 final 修飾的類不能被繼承。

現在,我們可以看看 AOP 的定義:面向切面編程,核心原理是

使用動態代理模式在方法執行前後或出現異常時加入相關邏輯

通過定義和前面代碼我們可以發現3點:

  • AOP 是基於動態代理模式。
  • AOP 是方法級別的。
  • AOP 可以分離業務代碼和關注點代碼(重複代碼),在執行業務代碼時,動態的注入關注點代碼。切面就是關注點代碼形成的類。

4. Spring AOP

前文提到 JDK 代理和 CGLIB 代理兩種動態代理。優秀的 Spring 框架把兩種方式在底層都集成了進去,我們無需擔心自己去實現動態生成代理。那麼,Spring是如何生成代理對象的?

  1. 創建容器對象的時候,根據切入點表達式攔截的類,生成代理對象。
  2. 如果目標對象有實現接口,使用 JDK 代理。如果目標對象沒有實現接口,則使用 CGLIB 代理。然後從容器獲取代理後的對象,在運行期植入“切面”類的方法。通過查看 Spring 源碼,我們在 DefaultAopProxyFactory 類中,找到這樣一段話。
Spring AOP是什麼?你都拿它做什麼?

簡單的從字面意思看出:如果有接口,則使用 JDK 代理,反之使用 CGLIB ,這剛好印證了前文所闡述的內容。Spring AOP 綜合兩種代理方式的使用前提有會如下結論:如果目標類沒有實現接口,且 class 為 final 修飾的,則不能進行 Spring AOP 編程!

知道了原理,現在我們將自己手動實現 Spring 的 AOP:

Spring AOP是什麼?你都拿它做什麼?


Spring 的 XML 配置文件:

Spring AOP是什麼?你都拿它做什麼?


切入點表達式不在這裡介紹。參考 Spring AOP 切入點表達式(https://blog.csdn.net/keda8997110/article/details/50747923)

代碼的測試結果如下:

Spring AOP是什麼?你都拿它做什麼?

到這裡,我們已經全部介紹完Spring AOP。回到開篇的問題,我們拿它做什麼?


分享到:


相關文章: