AOP、AspectJ、Spring AOP、JDK動態代理、CGLib動態代理

Table of Contents

1. AOP介紹

2.AOP的實現

3.Spring AOP的兩種實現方式

4.AspectJ實現示例

5.JDK動態代理、CGLib動態代理 實現示例

6.小結


1. AOP介紹

AOP稱爲面向切面編程,它是一種編程思想,是對OOP的補充,可以進一步提高編程效率,在程序開發中主要用來解決一些系統層面上的問題,比如日誌,事務,權限等待,Struts2的攔截器設計就是基於AOP的思想,是個比較經典的例子。

 AOP的基本概念:

(1)Aspect(切面):通常是一個類,裏面可以定義切入點和通知

(2)JointPoint(連接點):程序執行過程中明確的點,一般是方法的調用

(3)Advice(通知):AOP在特定的切入點上執行的增強處理,有before,after,afterReturning,afterThrowing,around

(4)Pointcut(切入點):就是帶有通知的連接點,在程序中主要體現爲書寫切入點表達式

(5)Target(目標對象):就是被增強的目標類,也稱之爲委託類。

(6)AOP代理:AOP框架創建的對象,代理就是目標對象的加強。Spring AOP代理可以使JDK動態代理,也可以是CGLIB代理,前者基於接口,後者基於子類。


2.AOP的實現

AOP前面說過是編程思想,所以需要具體的實現方法來實現。

AOP的實現主要分爲靜態代理和動態代理,靜態代理的實現方式是AspectJ;而動態代理則以Spring AOP爲代表。

  • AspectJ(靜態)
    • AspectJ是語言級的實現,它擴展了Java語言,定義了AOP語法。
    • AspectJ在編譯期織入代碼,它有一個專門的編譯器,用來生成遵守Java字節碼規範的class文件。
  • Spring AOP(動態)
    • Spring AOP使用純Java實現,它不需要專門的編譯過程,也不需要特殊的類裝載器。
    • Spring AOP在運行時通過代理的方式織入代碼,只支持方法類型的連接點。
    • Spring支持對AspectJ的集成。

3.Spring AOP的兩種實現方式

  • JDK動態代理(依賴接口)
    • Java提供的動態代理技術,可以在運行時創建接口的代理實例。
    • Spring AOP默認採用此種方式,在接口的代理實例中織入代碼。
  • CGLib動態代理(不依賴接口)
    • 採用底層的字節碼技術,在運行時創建子類代理實例。
    • 當目標對象不存在接口時,Spring AOP會採用此種方式,在子類實例中織入代碼。

 

4.AspectJ實現示例

AspectJ是靜態代理的增強,所謂的靜態代理就是AOP框架會在編譯階段生成AOP代理類,因此也稱爲編譯時增強。

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


package test.staticProxy;

// 接口

public interface IUserDao {

void save();

void find();

}

//目標對象

class UserDao implements IUserDao{

@Override

public void save() {

System.out.println("模擬:保存用戶!");

}

@Override

public void find() {

System.out.println("模擬:查詢用戶");

}

}

/**

靜態代理

特點:

1. 目標對象必須要實現接口

2. 代理對象,要實現與目標對象一樣的接口

*/

class UserDaoProxy implements IUserDao{

// 代理對象,需要維護一個目標對象

private IUserDao target = new UserDao();

@Override

public void save() {

System.out.println("代理操作: 開啓事務...");

target.save(); // 執行目標對象的方法

System.out.println("代理操作:提交事務...");

}

@Override

public void find() {

target.find();

}

}

測試結果:

       

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

 

5.JDK動態代理、CGLib動態代理 實現示例

5.1 JDK動態代理

JDK動態代理通過反射來接收被代理的類,並且要求被代理的類必須實現一個接口。JDK動態代理的核心是InvocationHandler接口和Proxy類。

5.2 CGLIB動態代理

如果目標類沒有實現接口,那麼Spring AOP會選擇使用CGLIB來動態代理目標類。CGLIB(Code Generation Library),是一個代碼生成的類庫,可以在運行時動態的生成某個類的子類。注意:CGLIB是通過繼承的方式做的動態代理,因此如果某個類被標記爲final,那麼它是無法使用CGLIB做動態代理的。

5.3 JDK Proxy VS Cglib

JDK Proxy 的優勢:

  • 最小化依賴關係,減少依賴意味着簡化開發和維護,JDK 本身的支持,更加可靠;

  • 平滑進行 JDK 版本升級,而字節碼類庫通常需要進行更新以保證在新版上能夠使用;

Cglib 框架的優勢:

  • 可調用普通類,不需要實現接口;

  • 高性能;

6.小結

AspectJ在編譯時就增強了目標對象,Spring AOP的動態代理則是在每次運行時動態的增強,生成AOP代理對象。區別在於生成AOP代理對象的時機不同,相對來說AspectJ的靜態代理方式具有更好的性能,但是AspectJ需要特定的編譯器進行處理,而Spring AOP則無需特定的編譯器處理。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章