Java 5 引入標準元資料功能(JSR 175),為程式元素附加型別化註解並保留至執行期提供了官方支援。這對面向切面程式設計(AOP)影響深遠:元資料能擴展連接點模型,讓切點捕獲那些「無隱式簽名特徵」的橫切關注點(如交易、授權)。本文為兩部分系列之第一部分,涵蓋元資料核心概念、三大 AOP 系統的支援現況,並以交易管理為例展示設計演進五版本,逐步改善模組化與復用性。
@interface 定義註解型別,支援保留策略(SOURCE/CLASS/RUNTIME)。AOP 核心在於切點選取連接點。傳統切點依賴隱式屬性:靜態簽名(名稱、型別、參數)、詞法位置、動態屬性(控制流)。但對於「需交易管理的方法」、「需授權的操作」,隱式屬性無特徵可循,切點退化為冗長列舉:
pointcut transactedOps()
: execution(void Account.credit(..))
|| execution(void Account.debit(..))
|| execution(void Customer.setAddress(..)) ...;
引入 @Transactional 註解後,切點化繁為簡:
pointcut transactedOps() : execution(@Transactional * *.*(..));
但引入註解意味著類別必須攜帶對應標註,影響模組化。本文後續將展示如何演進設計以兼顧表達力與鬆耦合。
| 能力 | AspectJ 5 | AspectWerkz | JBoss AOP |
|---|---|---|---|
| 消費註解(切點匹配) | execution(@Tx * *(..))、@annotation(tx) 綁定上下文 | @Expression("execution(@Tx * *(..))") | XML: <pointcut expr="* *->@Tx(..)"/> |
| 依註解屬性過濾 | 語法支援 @Tx(value==RequiredNew),編譯期靜態檢查 | 僅執行期反射檢查 | 僅執行期反射檢查 |
| 供給註解(橫切附加) | declare annotation: * Account.*(..) : @Auth(...);、@DeclareAnnotation | 不支援 | XML <annotation-introduction> |
以銀行系統交易管理為例,展示逐步重構:

public aspect BankingTxMgmt {
pointcut transactedOps()
: execution(void Customer.setAddress(..)) || ...;
Object around() : transactedOps() { ... 交易邏輯 ... }
}
缺點:切點特定於系統,不可重用;系統變更須修改切面(N 對 1 耦合)。

public abstract aspect TxMgmt {
public abstract pointcut transactedOps();
Object around() : transactedOps() { ... 通用交易邏輯 ... }
}
public aspect BankingTxMgmt extends TxMgmt {
public pointcut transactedOps() : ... 同版本 1 列舉 ...;
}
改進:邏輯重用;殘留:子切面仍與所有相關類別強耦合。

public class Customer {
// 業務方法...
private static aspect TxMgmtParticipant extends TxMgmt {
public pointcut transactedOps()
: execution(void Customer.setAddress(..)) || ...;
}
}
優勢:類別變更只改自身巢狀切面,耦合從 N 降為 1;切點可用通配符簡化(execution(public * Customer.*(..)))。
代價:類別強依賴基底切面;必須顯式「參與」才生效。

public aspect MetadataDrivenTxMgmt extends TxMgmt {
public pointcut transactedOps()
: execution(@Transactional * *.*(..));
}
類別改以 @Transactional 標註需交易的方法。
效果:建立方法與切面的 1:1 依賴(僅透過註解型別);基底切面可選、可替換;支援 Participant 與元資料混合;可從業務註解(@Purchase)衍生技術註解。

當類別多數方法需同組註解時,改由巢狀「註解者切面」批量宣告:
public class Customer {
public void setAddress(Address a) { ... }
public void addAccount(Account a) { ... }
private static aspect Annotator {
declare annotation: public Customer.*(..): @Transactional;
}
}
進階:橋接切面將業務註解轉換為技術註解:
public aspect BusinessTransactionBridge {
declare annotation: @Purchase *.*(..): @Transactional;
declare annotation: @OrderProcessing *.*(..): @Transactional;
}
類別只標註業務語義(@Purchase),橋接切面映射至 @Transactional,實現關注點分離的極致。
元資料讓 AOP 能以更簡單切點捕獲複雜橫切語義。五版本演進展示:從硬編碼切點 → 抽象基底 → Participant 分散耦合 → 元資料驅動 → 切面供給註解,每一步都提升模組化與演進彈性。第二部分將深入探討多維介面觀點、抽象註解設計準則、無知性原則與 AOP 採用策略。