Java代理和動態代理機制分析和應用
一、概述
代理是一種常用的設計模式,其目的就是為其他物件提供一個代理以控制對某個物件的訪問。代理類負責為委託類預處理訊息,過濾訊息並轉發訊息,以及進行訊息被委託類執行後的後續處理。根據代理類的生成時間不同可以將代理分為靜態代理和動態代理兩種。
二、代理的優點
a.隱藏委託類的實現,呼叫者只需要和代理類進行互動即可。
b.解耦,在不改變委託類程式碼情況下做一些額外處理,比如新增初始判斷及其他公共操作。
三、應用場景
代理的使用場景很多,struts2中的 action 呼叫, hibernate的懶載入, spring的 AOP無一不用到代理。總結起來可分為以下幾類:
- 在原方法執行之前和之後做一些操作,可以用代理來實現(比如記錄Log,做事務控制等)。
- 封裝真實的主題類,將真實的業務邏輯隱藏,只暴露給呼叫者公共的主題介面。
- 在延遲載入上的應用。
四、靜態代理
所謂靜態代理也就是在程式執行前就已經存在代理類的位元組碼檔案,代理類和委託類的關係在執行前就確定了。
優點:業務類只需要關注業務邏輯本身,保證了業務類的重用性。這是代理的共有優點。
缺點:
1)代理物件的一個介面只服務於一種型別的物件,如果要代理的方法很多,勢必要為每一種方法都進行代理,靜態代理在程式規模稍大時就無法勝任了。
2)如果介面增加一個方法,除了所有實現類需要實現這個方法外,所有代理類也需要實現此方法。增加了程式碼維護的複雜度。
另外,如果要按照上述的方法使用代理模式,那麼真實角色(委託類)必須是事先已經存在的,並將其作為代理物件的內部屬性。但是實際使用時,一個真實角色必須對應一個代理角色,如果大量使用會導致類的急劇膨脹;此外,如果事先並不知道真實角色(委託類),該如何使用代理呢?這個問題可以通過Java的動態代理類來解決。
五、動態代理
在java的動態代理API中,有兩個重要的類和介面,一個是 InvocationHandler(Interface)、另一個則是 Proxy(Class),這一個類和介面是實現我們動態代理所必須用到的。
1)InvocationHandler(Interface)
InvocationHandler是負責連線代理類和委託類的中間類必須實現的介面,它自定義了一個 invoke 方法,用於集中處理在動態代理類物件上的方法呼叫,通常在該方法中實現對委託類的代理訪問。
InvocationHandler 的核心方法
Object invoke(Object proxy, Method method, Object[] args)
- proxy 該引數為代理類的例項
- method 被呼叫的方法物件
- args 呼叫method物件的方法引數
該方法也是InvocationHandler介面所定義的唯一的一個方法,該方法負責集中處理動態代理類上的所有方法的呼叫。呼叫處理器根據這三個引數進行預處理或分派到委託類例項上執行。
2)Proxy(Class)
Proxy是 Java 動態代理機制的主類,它提供了一組靜態方法來為一組介面動態地生成代理類及其物件。
Proxy 的靜態方法
static InvocationHandler getInvocationHandler(Object proxy)
該方法用於獲取指定代理物件所關聯的呼叫處理器static Class getProxyClass(ClassLoader loader, Class[] interfaces)
該方法用於獲取關聯於指定類裝載器和一組介面的動態代理類的類物件static boolean isProxyClass(Class cl)
該方法用於判斷指定類物件是否是一個動態代理類 static Object newProxyInstance(ClassLoader loader, Class[] interfaces,InvocationHandler h)
- loader 指定代理類的ClassLoader載入器
- interfaces 指定代理類要實現的介面
- h: 表示的是當我這個動態代理物件在呼叫方法的時候,會關聯到哪一個InvocationHandler物件上
該方法用於為指定類裝載器、一組介面及呼叫處理器生成動態代理類例項
使用Java 動態代理的兩個重要步驟
- 通過實現 InvocationHandler 介面建立自己的呼叫處理器;
通過為Proxy類的newProxyInstance方法指定代理類的ClassLoader 物件和代理要實現的interface以及呼叫處理器InvocationHandler物件 來建立動態代理類的物件;
動態代理的優缺點
優點
1.動態代理類的位元組碼在程式執行時由Java反射機制動態生成,無需程式設計師手工編寫它的原始碼。
2.動態代理類不僅簡化了程式設計工作,而且提高了軟體系統的可擴充套件性,因為Java 反射機制可以生成任意型別的動態代理類。
缺點
JDK的動態代理機制只能代理實現了介面的類,而不能實現介面的類就不能實現JDK的動態代理,cglib是針對類來實現代理的,他的原理是對指定的目標類生成一個子類,並覆蓋其中方法實現增強,但因為採用的是繼承,所以不能對final修飾的類進行代理。