在spring框架中使用了兩種代理方式:
1.JDK自帶的動態代理。
2.Spring框架自己提供的CGLIB的方式。
這兩種也是Spring框架核心AOP的基礎。
在詳細講解上述提到的動態代理和CGLIB前,需要明白如下內容:
代理,靜態代理,動態代理。
一、概述
1、什麼是代理(Java架構師交流企鵝裙*/*:1028678754 )
代理的概念容易理解,比如:微商,簡單來說微商就是替廠家賣商品。當我們從微商(代理)那裡買東西時通常不知道背後的商家究竟是誰,也就是說,委託者對我們來說是不可見的。作為微商,有其自己的目標客戶,這也相當於為廠家做了一次過濾。把微商和廠家進一步抽象,微商可以抽象為代理類,廠家可抽象為委託類(被代理類)。透過微商和廠家特點可知,透過使用代理,通常有兩個優點:
其一:可以隱藏委託類的實現;
其二:可以實現客戶與委託類間的解耦,在不修改委託類程式碼的情況下能夠做一些額外的處理。
2、靜態代理
若代理類在程式執行前就已經存在,那麼這種代理方式被成為靜態代理。
這種情況下的代理類通常都是我們在Java程式碼中定義的。 通常情況下,靜態代理中的代理類和委託類會實現同一介面或是派生自相同的父類。 下面我們用Vendor類代表生產廠家,BusinessAgent類代表微商代理,來介紹下靜態代理的簡單實現。
委託類和代理類都實現了Sell介面,Sell介面的定義如下:
Vendor類的定義如下:
從BusinessAgent類的定義我們可以瞭解到,靜態代理可以透過聚合來實現,讓代理類持有一個委託類的引用即可。
如果需要增加一個需求:給Vendor類增加一個過濾功能,不可以賣給學生。透過靜態代理,我們無需修改Vendor類的程式碼就可以實現,只需在BusinessAgent類中的sell方法中新增一個判斷即可。如上圖可以。
這對應著我們上面提到的使用代理的第二個優點:可以實現客戶與委託類間的解耦,在不修改委託類程式碼的情況下能夠做一些額外的處理。靜態代理的侷限在於執行前必須編寫好代理類,下面我們重點來介紹下執行時生成代理類的動態代理方式,即動態代理機制。
二、動態代理
代理類在程式執行時建立的代理方式被成為 動態代理。 也就是說,這種情況下,代理類並不是在Java程式碼中定義的,而是在執行時根據我們在Java程式碼中的“指示”動態生成的。相比於靜態代理, 動態代理的優勢在於可以很方便的對代理類的函式進行統一的處理,而不用修改每個代理類的函式。 這麼說比較抽象,下面我們結合一個例項來介紹一下動態代理的這個優勢是怎麼體現的。
現在,假設我們要實現這樣一個需求:在執行委託類中的方法之前輸出“before”,在執行完畢後輸出“after”。我們還是以上面例子中的Vendor類作為委託類,BusinessAgent類作為代理類來進行介紹。首先我們來使用靜態代理來實現這一需求,相關程式碼如下:
從以上程式碼中我們可以瞭解到,透過靜態代理實現我們的需求需要我們在每個方法中都新增相應的邏輯,這裡只存在兩個方法所以工作量還不算大,假如Sell介面中包含上百個方法呢?這時候使用靜態代理就會編寫許多冗餘程式碼。透過使用動態代理,我們可以做一個“統一指示”,從而對所有代理類的方法進行統一處理,而不用逐一修改每個方法。下面我們來具體介紹下如何使用動態代理方式實現我們的需求。
2、使用動態代理
(1)InvocationHandler介面
在使用動態代理時,我們需要定義一個位於代理類與委託類之間的中介類,這個中介類被要求實現InvocationHandler介面,這個介面的定義如下:
從InvocationHandler這個名稱我們就可以知道,實現了這個介面的中介類用做“呼叫處理器”。當我們呼叫代理類物件的方法時,這個“呼叫”會轉送到invoke方法中,代理類物件作為proxy引數傳入,引數method標識了我們具體呼叫的是代理類的哪個方法,args為這個方法的引數。這樣一來,我們對代理類中的所有方法的呼叫都會變為對invoke的呼叫,這樣我們可以在invoke方法中新增統一的處理邏輯(也可以根據method引數對不同的代理類方法做不同的處理)。因此我們只需在中介類的invoke方法實現中輸出“before”,然後呼叫委託類的invoke方法,再輸出“after”。下面我們來一步一步具體實現它。
(2)委託類的定義
動態代理方式下,要求委託類必須實現某個介面,這裡我們實現的是Sell介面。委託類Vendor類的定義如下:
(3)中介類
上面我們提到過,中介類必須實現InvocationHandler介面,作為呼叫處理器”攔截“對代理類方法的呼叫。中介類的定義如下:
從以上程式碼中我們可以看到,中介類持有一個委託類物件引用,在invoke方法中呼叫了委託類物件的相應方法,透過聚合方式持有委託類物件引用,把外部對invoke的呼叫最終都轉為對委託類物件的呼叫。下面我們來介紹一下如何”指示“以動態生成代理類。
(4)動態生成代理類
動態生成代理類的相關程式碼如下:
在以上程式碼中,我們呼叫Proxy類的newProxyInstance方法來獲取一個代理類例項。這個代理類實現了我們指定的介面並且會把方法呼叫分發到指定的呼叫處理器。這個方法的宣告如下:
public static Object newProxyInstance(ClassLoader loader, Class<?>[] interfaces, InvocationHandler h) throws IllegalArgumentException
在spring框架中使用了兩種代理方式:
1.JDK自帶的動態代理。
2.Spring框架自己提供的CGLIB的方式。
這兩種也是Spring框架核心AOP的基礎。
在詳細講解上述提到的動態代理和CGLIB前,需要明白如下內容:
代理,靜態代理,動態代理。
一、概述
1、什麼是代理(Java架構師交流企鵝裙*/*:1028678754 )
代理的概念容易理解,比如:微商,簡單來說微商就是替廠家賣商品。當我們從微商(代理)那裡買東西時通常不知道背後的商家究竟是誰,也就是說,委託者對我們來說是不可見的。作為微商,有其自己的目標客戶,這也相當於為廠家做了一次過濾。把微商和廠家進一步抽象,微商可以抽象為代理類,廠家可抽象為委託類(被代理類)。透過微商和廠家特點可知,透過使用代理,通常有兩個優點:
其一:可以隱藏委託類的實現;
其二:可以實現客戶與委託類間的解耦,在不修改委託類程式碼的情況下能夠做一些額外的處理。
2、靜態代理
若代理類在程式執行前就已經存在,那麼這種代理方式被成為靜態代理。
這種情況下的代理類通常都是我們在Java程式碼中定義的。 通常情況下,靜態代理中的代理類和委託類會實現同一介面或是派生自相同的父類。 下面我們用Vendor類代表生產廠家,BusinessAgent類代表微商代理,來介紹下靜態代理的簡單實現。
委託類和代理類都實現了Sell介面,Sell介面的定義如下:
Vendor類的定義如下:
從BusinessAgent類的定義我們可以瞭解到,靜態代理可以透過聚合來實現,讓代理類持有一個委託類的引用即可。
如果需要增加一個需求:給Vendor類增加一個過濾功能,不可以賣給學生。透過靜態代理,我們無需修改Vendor類的程式碼就可以實現,只需在BusinessAgent類中的sell方法中新增一個判斷即可。如上圖可以。
這對應著我們上面提到的使用代理的第二個優點:可以實現客戶與委託類間的解耦,在不修改委託類程式碼的情況下能夠做一些額外的處理。靜態代理的侷限在於執行前必須編寫好代理類,下面我們重點來介紹下執行時生成代理類的動態代理方式,即動態代理機制。
二、動態代理
代理類在程式執行時建立的代理方式被成為 動態代理。 也就是說,這種情況下,代理類並不是在Java程式碼中定義的,而是在執行時根據我們在Java程式碼中的“指示”動態生成的。相比於靜態代理, 動態代理的優勢在於可以很方便的對代理類的函式進行統一的處理,而不用修改每個代理類的函式。 這麼說比較抽象,下面我們結合一個例項來介紹一下動態代理的這個優勢是怎麼體現的。
現在,假設我們要實現這樣一個需求:在執行委託類中的方法之前輸出“before”,在執行完畢後輸出“after”。我們還是以上面例子中的Vendor類作為委託類,BusinessAgent類作為代理類來進行介紹。首先我們來使用靜態代理來實現這一需求,相關程式碼如下:
從以上程式碼中我們可以瞭解到,透過靜態代理實現我們的需求需要我們在每個方法中都新增相應的邏輯,這裡只存在兩個方法所以工作量還不算大,假如Sell介面中包含上百個方法呢?這時候使用靜態代理就會編寫許多冗餘程式碼。透過使用動態代理,我們可以做一個“統一指示”,從而對所有代理類的方法進行統一處理,而不用逐一修改每個方法。下面我們來具體介紹下如何使用動態代理方式實現我們的需求。
2、使用動態代理
(1)InvocationHandler介面
在使用動態代理時,我們需要定義一個位於代理類與委託類之間的中介類,這個中介類被要求實現InvocationHandler介面,這個介面的定義如下:
從InvocationHandler這個名稱我們就可以知道,實現了這個介面的中介類用做“呼叫處理器”。當我們呼叫代理類物件的方法時,這個“呼叫”會轉送到invoke方法中,代理類物件作為proxy引數傳入,引數method標識了我們具體呼叫的是代理類的哪個方法,args為這個方法的引數。這樣一來,我們對代理類中的所有方法的呼叫都會變為對invoke的呼叫,這樣我們可以在invoke方法中新增統一的處理邏輯(也可以根據method引數對不同的代理類方法做不同的處理)。因此我們只需在中介類的invoke方法實現中輸出“before”,然後呼叫委託類的invoke方法,再輸出“after”。下面我們來一步一步具體實現它。
(2)委託類的定義
動態代理方式下,要求委託類必須實現某個介面,這裡我們實現的是Sell介面。委託類Vendor類的定義如下:
(3)中介類
上面我們提到過,中介類必須實現InvocationHandler介面,作為呼叫處理器”攔截“對代理類方法的呼叫。中介類的定義如下:
從以上程式碼中我們可以看到,中介類持有一個委託類物件引用,在invoke方法中呼叫了委託類物件的相應方法,透過聚合方式持有委託類物件引用,把外部對invoke的呼叫最終都轉為對委託類物件的呼叫。下面我們來介紹一下如何”指示“以動態生成代理類。
(4)動態生成代理類
動態生成代理類的相關程式碼如下:
在以上程式碼中,我們呼叫Proxy類的newProxyInstance方法來獲取一個代理類例項。這個代理類實現了我們指定的介面並且會把方法呼叫分發到指定的呼叫處理器。這個方法的宣告如下:
public static Object newProxyInstance(ClassLoader loader, Class<?>[] interfaces, InvocationHandler h) throws IllegalArgumentException