知識庫 / Spring RSS 訂閱

對比 Spring AOP 和 AspectJ

Spring
HongKong
4
02:22 PM · Dec 06 ,2025

1. 簡介

今天有很多可用的 AOP 庫,這些庫需要能夠回答一系列問題:

  • 它是否與我的現有或新應用程序兼容?
  • 我可以在哪裏實現 AOP?
  • 它與我的應用程序集成需要多快?
  • 它的性能開銷是多少?

在本文中,我們將探討如何回答這些問題,並介紹 Spring AOP 和 AspectJ – Java 中最流行的兩個 AOP 框架。

2. AOP 概念

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

  • 方面 (Aspect) – 是一種在應用程序的多個地方分散使用的標準代碼/功能,通常與實際的業務邏輯不同(例如,事務管理)。每個方面都專注於特定的橫切關注功能。
  • 連接點 (Joinpoint) – 是程序執行過程中的特定點,例如方法執行、構造函數調用或字段賦值。
  • 建議 (Advice) – 方面在特定連接點執行的操作。
  • 切入點 (Pointcut) – 是一正則表達式,用於匹配連接點。當任何連接點與切入點匹配時,與該切入點關聯的指定建議就會被執行。
  • 織入 (Weaving) – 是將方面與目標對象鏈接以創建被建議的對象的過程。

3. Spring AOP 和 AspectJ

現在,我們來探討 Spring AOP 和 AspectJ 在多個維度上的表現——例如,其能力、目標、織入方式、內部結構、切入點和簡潔性。

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 利用三種不同的編織類型:

  • 編譯時編織 (Compile-time weaving):AspectJ 編譯器將我們的方面代碼和應用程序源代碼作為輸入,並生成編織後的類文件作為輸出。
  • 預編譯編織 (Post-compile weaving):也稱為二進制編織。它用於將現有的類文件和 JAR 文件與我們的方面編織在一起。
  • 加載時編織 (Load-time weaving):這與前述二進制編織類似,但編織延遲到類加載器將類文件加載到 JVM 之後。

關於 AspectJ 本身的更深入信息,請參閲這篇文章。

由於 AspectJ 使用編譯時和加載時編織,因此 Spring AOP 使用運行時編織

通過運行時編織,在應用程序執行期間,使用目標對象的代理(使用 JDK 動態代理或 CGLIB 代理,後面會討論)將方面編織到應用程序中。

3.3. 內部結構與應用

Spring AOP 是一種基於代理的 AOP 框架。這意味着為了將方面應用於目標對象,它會創建該對象的代理。這通過以下兩種方式實現:

  1. JDK 動態代理 – 這是 Spring AOP 的首選方式。只要目標對象實現了任何一個接口,就會使用 JDK 動態代理
  2. CGLIB 代理 – 如果目標對象未實現任何接口,則可以使用 CGLIB 代理

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

另一方面,AspectJ 在運行時不做任何操作,因為類直接使用 AspectJ 編譯器進行編譯。

因此,與 Spring AOP 不同,它不需要使用任何設計模式。為了將方面織入代碼中,它引入了其編譯器 AspectJ 編譯器 (ajc),通過它,我們編譯程序並運行它,同時提供一個小型(< 100K)的運行時庫。

3.4. Joinpoint

在第 3.3 節中,我們已經展示了 Spring AOP 基於代理模式。因此,它需要子類化目標 Java 類並相應地應用橫切關注點。

但是,這存在一個限制。我們不能將橫切關注點(或方面)應用於“final” 類,因為它們不能被重寫,從而會導致運行時異常。

同樣,對靜態和 final 方法也適用。Spring 方面不能應用於它們,因為它們不能被重寫。因此,由於這些限制,Spring AOP 僅支持方法執行 joinpoint。

然而,AspectJ 在運行時直接將橫切關注點編織到實際代碼中。與 Spring AOP 不同,它不需要子類化目標對象,因此還支持許多其他 joinpoint。以下是支持的 joinpoint 總結:

Joinpoint Spring AOP 支持 AspectJ 支持
Method Call
Method Execution
Constructor Call
Constructor Execution
Static initializer execution
Object initialization
Field reference
Field assignment
Handler execution
Advice execution

此外,在 Spring AOP 中,方面不應用於調用的方法在同一類中。

這顯然是因為當我們調用同一類中的方法時,我們並沒有調用 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. Summary

下表總結了 Spring AOP 和 AspectJ 之間的主要區別:

Spring AOP AspectJ
使用純 Java 實現 使用 Java 編程語言的擴展實現
無需單獨編譯過程 需要 AspectJ 編譯器 (ajc),除非設置 LTW
僅支持運行時編織 不支持運行時編織。支持編譯時、預編譯和加載時編織
功能較弱 – 僅支持方法級別的編織 功能更強大 – 可以編織字段、方法、構造函數、靜態初始化器、最終類/方法等…
只能在 Spring 容器管理的 Bean 上實現 可以在所有域對象上實現
僅支持方法執行點切 支持所有點切
創建目標對象的代理,並在這些代理上應用方面 方面在執行應用程序之前直接編織到代碼中 (在運行時之前)
比 AspectJ 慢得多 性能更好
易於學習和應用 與 Spring AOP 相比,更復雜

5. 選擇合適的框架

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

簡單來説,選擇主要取決於我們的需求:

  • 框架:如果應用程序未使用 Spring 框架,那麼我們沒有選擇使用 Spring AOP 的選擇,因為它無法管理超出 Spring 容器範圍的任何內容。但是,如果我們的應用程序完全使用 Spring 框架構建,那麼我們可以使用 Spring AOP,因為它易於學習和應用
  • 靈活性:鑑於有限的 Joinpoint 支持,Spring AOP 不是一個完整的 AOP 解決方案,但它解決了程序員最常見的問題。儘管如果我們想深入挖掘並充分利用 AOP 的能力,並希望獲得來自各種 Joinpoint 的支持,那麼 AspectJ 是選擇
  • 性能:如果我們使用有限的 Aspect,那麼性能差異可以忽略不計。但是,在某些情況下,應用程序可能包含超過十萬個 Aspect。我們不會希望在這些情況下使用運行時編織,因此最好選擇 AspectJ。AspectJ 據稱比 Spring AOP 快 8 到 35 倍
  • 最佳組合:這兩個框架完全兼容。我們可以在可能的情況下利用 Spring AOP,同時使用 AspectJ 以獲得前者的不支持的 Joinpoint 的支持

6. 結論

本文分析了 Spring AOP 和 AspectJ 在多個關鍵領域。

我們比較了這兩種 AOP 方法,包括其靈活性以及它們與我們應用程序的適配性。

user avatar
0 位用戶收藏了這個故事!
收藏

發佈 評論

Some HTML is okay.