1. 程式人生 > 實用技巧 >淺談設計模式之代理設計模式

淺談設計模式之代理設計模式

什麼是代理模式

為其他物件提供一種代理以控制對這個物件的訪問。

為什麼使用代理模式

中介隔離:在某些情況下,一個客戶類不想或者不能直接引用一個委託物件,而代理類物件可以在客戶類和委託物件之間起到中介的作用,其特徵是代理類和委託類實現相同的介面。

開閉原則,增加功能:代理類除了是客戶類和委託類的中介之外,我們還可以通過給代理類增加額外的功能來擴充套件委託類的功能,這樣做我們只需要修改代理類而不需要再修改委託類,符合程式碼設計的開閉原則。代理類主要負責為委託類預處理訊息、過濾訊息、把訊息轉發給委託類,以及事後對返回結果的處理等。代理類本身並不真正實現服務,而是同過呼叫委託類的相關方法,來提供特定的服務。真正的業務功能還是由委託類來實現,但是可以在業務功能執行的前後加入一些公共的服務。例如我們想給專案加入快取、日誌這些功能,我們就可以使用代理類來完成,而沒必要開啟已經封裝好的委託類。

代理模式實現原理

代理模式主要包含三個角色,即抽象主題色(Subject)、委託類角色(被代理角色,Proxied)以及代理類角色(Proxy)

抽象主題角色(Subject):可以是介面,也可以是抽象類

委託類角色(proxied):真實主題角色,業務邏輯的具體執行者

代理類角色(Proxy):內部含有對真實物件RealSubject的引用,負責對真實主題角色的呼叫,並在真實主題角色處理前後做預處理和後處理

代理模式應用場景

SpringAop、日誌收集、許可權控制、過濾器、RPC遠端呼叫

代理模式建立的方式

靜態代理 和 動態代理

靜態代理

靜態代理是由程式設計師建立或工具生成代理類的原始碼,再編譯代理類。

所謂靜態也就是在程式執行前就已經存在代理類的位元組碼檔案,代理類和委託類的關係在執行前就確定了。

總結:自己手寫代理類就是靜態代理。

動態代理

動態代理是在實現階段不用關心代理類,而在執行階段才指定哪一個物件。

動態代理類的原始碼是在程式執行期間由JVM根據反射等機制動態的生成 。

JDK動態代理

JDK動態代理的一般步驟如下:

1.建立被代理的介面和類;

2.實現InvocationHandler介面,對目標介面中宣告的所有方法進行統一處理;

3.呼叫Proxy的靜態方法,建立代理類並生成相應的代理物件;

CGLIB動態代理

Cglib是一個強大的,高效能,高質量的程式碼生成類庫。它可以在執行期擴充套件JAVA類與實現JAVA介面。其底層實現是通過ASM位元組碼處理框架來轉換位元組碼並生成新的類。大部分功能實際上是ASM所提供的,Cglib只是封裝了ASM,簡化了ASM操作,實現了執行期生成新的class。

CGLIB原理

執行時動態的生成一個被代理類的子類(通過ASM位元組碼處理框架實現),子類重寫了被代理類中所有非final的方法。在子類中採用方法攔截的技術攔截所有父類方法的呼叫,順勢植入橫切邏輯。

Cglib優缺點

優點:JDK動態代理要求被代理的類必須實現介面,當需要代理的類沒有實現介面時Cglib代理是一個很好的選擇。另一個優點是Cglib動態代理比使用java反射的JDK動態代理要快

缺點:對於被代理類中的final方法,無法進行代理,因為子類中無法重寫final函式

CGLIB代理實現

實現MethodInterceptor介面的intercept方法後,所有生成的代理方法都呼叫這個方法。

intercept方法的具體引數有

1.obj 目標類的例項
1.method 目標方法例項(通過反射獲取的目標方法例項)
2.args 目標方法的引數
3.proxy 代理類的例項

該方法的返回值就是目標方法的返回值。

靜態代理與動態代理區別

靜態代理需要自己寫代理類,而動態代理不需要寫代理類。

JDK動態代理與CGLIB實現區別

JDK動態代理底層實現:

JDK的動態代理使用Java的反射技術生成動態代理類,只能代理實現了介面的類, 沒有實現介面的類不能實現動態代理。

CGLIB動態代理底層實現:

執行時動態的生成一個被代理類的子類(通過ASM位元組碼處理框架實現),子類重寫了被代理類中所有非final的方法,在子類中採用方法攔截的技術攔截所有父類方法的呼叫,不需要被代理類物件實現介面,從而CGLIB動態代理效率比Jdk動態代理反射技術效率要高。

Spring中強制使用CGLIB代理配置

新增CGLIB庫,SPRING_HOME/cglib/*.jar
在spring配置檔案中加入<aop:aspectj-autoproxy proxy-target-class="true"/>