Aspectj與Spring AOP的對比分析

1、簡介

今天有多個可用的 AOP 庫, 它們需要能夠回答許多問題:

1、是否與用戶現有的或新的應用程序兼容?

2、在哪裡可以實現 AOP?

3、與自己的應用程序集成多快?

4、性能開銷是多少?

在本文中, 我們將研究如何回答這些問題, 並介紹 Spring aop 和 AspectJ, 這是 Java 的兩個最受歡迎的 aop 框架。

2、AOP概念

在開始之前, 讓我們對術語和核心概念進行快速、高層次的審查:

Aspect —— 一種標準代碼/功能, 分散在應用程序中的多個位置, 通常與實際的業務邏輯不同 (例如, 事務管理)。每個方面都側重於特定的跨裁剪功能

Joinpoint —— 它是執行程序 (如方法執行、構造函數調用或字段分配) 期間的特定點

Advice —— 特定 joinpoint 中的方面所采取的行動

Pointcut —— 與 joinpoint 匹配的正則表達式。每次連接點與切入點匹配時, 都將執行與該切入點關聯的指定建議。

Weaving —— 將各方面與目標對象鏈接起來以創建建議對象的過程

3、Spring AOP 和 AspectJ

現在, 讓我們在一些維度上討論 Spring AOP 和 AspectJ —— 例如功能、目標、Weaving(織入)、內部結構、joinpoints 和簡單性。

3.1、能力和目標

簡單地說, Spring AOP 和 AspectJ 有不同的目標。

Spring aop 旨在提供一個跨 Spring IoC 的簡單的 aop 實現, 以解決程序員面臨的最常見問題。它不打算作為一個完整的 AOP 解決方案 —— 它隻能應用於由 Spring 容器管理的 bean。

另一方面, AspectJ 是原始的 aop 技術, 目的是提供完整的 aop 解決方案。它更健壯, 但也比 Spring AOP 復雜得多。還值得註意的是, AspectJ 可以在所有域對象中應用。

3.2、Weaving(織入)

AspectJ 和 Spring AOP 都使用不同類型的編織, 這會影響它們在性能和易用性方面的行為。

AspectJ 使用三種不同類型的Weaving:

編譯時 Weaving: AspectJ 編譯器作為輸入我們的方面的源代碼和我們的應用, 並產生一個織入類文件作為輸出;

編譯後 Weaving: 這也稱為二進制織入。它是用來織入現有的類文件和 JAR 文件與我們的方面;

加載時間 Weaving: 這就像前二進制織入, 不同的是織入被推遲, 直到類加載程序加載類文件到 JVM。

要瞭解更多關於 AspectJ 本身的詳細信息, 請 閱讀此文。

當 AspectJ 使用編譯時和class文件加載時織入時,Spring AOP 利用運行時織入。

使用運行時編織, 這些方面在使用目標對象的代理執行應用程序時被編織-使用 JDK 動態代理或 CGLIB 代理 (在下一點討論):

3.3、內部結構與應用

Spring aop 是基於代理的 aop 框架。這意味著, 要實現目標對象的各個方面, 它將創建該對象的代理。使用以下兩種方法之一實現:

1、JDK 動態代理 —— Spring AOP 的首選方式。隻要目標對象實現甚至一個接口, 就會使用 JDK 動態代理;

2、CGLIB 代理 —— 如果目標對象沒有實現接口, 則可以使用 CGLIB 代理。

我們可以從 官方文檔 中瞭解有關 Spring AOP 代理機制的更多信息。

另一方面, AspectJ 在運行時不做任何事情, 因為類是直接用方面進行編譯的。

與 Spring AOP 不同, 它不需要任何設計模式。為瞭編織代碼的各個方面, 它引入瞭稱為 AspectJ 編譯器 (ajc) 的編譯器, 通過它編譯我們的程序, 然後通過提供一個小型 (100K) 運行時庫來運行它。

3.4、Joinpoints

在3.3 節中, 我們顯示瞭 Spring AOP 是基於代理模式的。因此, 它需要將目標 Java 類分類, 並相應地應用交叉問題。

但這是有限制的。我們不能在 “最終” 類中應用交叉問題 (或方面), 因為它們不能被重寫, 因此會導致運行時異常。

同樣適用於靜態和最終方法。不能將 Spring 方面應用於它們, 因為它們不能被覆蓋。因此, 由於這些限制, Spring AOP 隻支持方法執行連接點。

然而, AspectJ 在運行前直接將橫切關註點編織到實際代碼中。與 Spring AOP 不同, 它不需要對目標對象進行子類, 因此也支持許多其他 joinpoints。

以下是支持的 joinpoints 的摘要:

Joinpoint Spring AOP Supported AspectJ Supported
Method Call No Yes
Method Execution Yes Yes
Constructor Call No Yes
Constructor Execution No Yes
Static initializer execution No Yes
Object initialization No Yes
Field reference No Yes
Field assignment No Yes
Handler execution No Yes
Advice execution No Yes

還值得註意的是, 在 Spring AOP 中, aspects不應用於在同一個類中相互調用的方法。

這顯然是因為當我們調用同一類中的方法時, 我們就不會調用 Spring AOP 提供的代理的方法。如果我們需要這個功能, 那麼我們必須在不同的 bean 中定義一個單獨的方法, 或者使用 AspectJ。

3.5、簡單性

Spring AOP 顯然更簡單, 因為它不會在我們的構建過程中引入任何額外的編譯器或織入。它使用運行時編織, 因此它與我們通常的構建過程無縫集成。雖然它看起來很簡單, 但它隻適用於由 Spring 管理的 bean。

但是, 要使用 AspectJ, 我們需要引入 AspectJ 編譯器 (ajc) 並重新打包所有的庫 (除非我們切換到編譯後或加載時間的織入)。

當然, 這比前者更復雜, 因為它引入瞭 AspectJ Java 工具 (包括編譯器 (ajc)、調試器 (ajdb)、文檔生成器 (ajdoc)、程序結構瀏覽器 (ajbrowser)), 我們需要將它們與我們的 IDE 或生成工具。

3.6、性能

就性能而言, 編譯時織入比運行時織入快得多。Spring AOP 是基於代理的框架, 因此在應用程序啟動時會創建代理。另外, 每個方面還有一些方法調用, 這會對性能產生負面影響。

另一方面, AspectJ 在應用程序執行之前將這些方面編織到主代碼中, 因此沒有額外的運行時開銷, 與 Spring AOP 不同。

基於這些原因, 基準表明 AspectJ 的速度幾乎比 Spring AOP 快8到35倍。

4、總結

此快速表總結瞭 Spring AOP 和 AspectJ 之間的關鍵區別:

Spring AOP AspectJ
在純 Java 中實現 使用 Java 編程語言的擴展實現
不需要單獨的編譯過程 除非設置 LTW,否則需要 AspectJ 編譯器 (ajc)
隻能使用運行時織入 運行時織入不可用。支持編譯時、編譯後和加載時織入
功能不強-僅支持方法級編織 更強大 – 可以編織字段、方法、構造函數、靜態初始值設定項、最終類/方法等……。
隻能在由 Spring 容器管理的 bean 上實現 可以在所有域對象上實現
僅支持方法執行切入點 支持所有切入點
代理是由目標對象創建的, 並且切面應用在這些代理上 在執行應用程序之前 (在運行時) 前, 各方面直接在代碼中進行織入
比 AspectJ 慢多瞭 更好的性能
易於學習和應用 相對於 Spring AOP 來說更復雜

5、選擇正確的框架

如果我們分析瞭本節中提出的所有論點, 我們就會開始理解, 一個框架比另一個架構更好。

簡單地說, 選擇很大程度上取決於我們的要求:

框架: 如果應用程序沒有使用 spring 框架, 那麼我們就別無選擇, 隻能放棄使用 spring AOP 的想法, 因為它無法管理任何超出 spring 容器范圍的東西。但是, 如果我們的應用程序是完全使用 spring 框架創建的, 那麼我們可以使用 spring AOP, 因為它是簡單的學習和應用

靈活性: 由於有限的 joinpoint 支持, Spring aop 不是一個完整的 aop 解決方案, 但它解決瞭程序員面臨的最常見的問題。盡管如果我們想深入挖掘和開發 AOP 以達到其最大能力, 並希望得到廣泛的可用 joinpoints 的支持, 那麼最好選擇 AspectJ

性能: 如果我們使用的是有限的切面, 那麼就會有細微的性能差異。但有時, 應用程序有成千上萬個切面的情況。我們不想在這樣的情況下使用運行時編織, 所以最好選擇 AspectJ。AspectJ 已知的速度比 Spring AOP 快8到35倍

兩者的最佳之處: 這兩個框架都是完全兼容的。我們總是可以利用 Spring AOP; 隻要有可能, 仍然可以在不支持前者的地方使用 AspectJ 獲得支持

6、結論

在本文中, 我們分析瞭 Spring AOP 和 AspectJ 的幾個關鍵領域。

我們比較瞭兩種 AOP 方法的靈活性, 以及它們將如何輕松地適應我們的應用程序。

以上為個人經驗,希望能給大傢一個參考,也希望大傢多多支持WalkonNet。

推薦閱讀: