2017-10-4(動態代理)

wyman_1007發表於2018-01-23

代理分為靜態代理和動態代理。

  • 靜態代理
    可以看下面程式碼
/**
* 靜態代理中代理類和委託類也常常繼承同一父類或實現同一介面。
* 普通業務類
* 通過介面更加靈活實現代理模式
*/

public interface Subject {
void visit();
}
/**
* 委託類
* 代理類和真實業務類都需要實現業務類的介面
*/

public class RealSubject implements Subject{
@Override
public void visit() {
//真實業務具體邏輯
System.out.println("Real Subject");
}
}
/**
* 代理類
* 代理類和委託類都需要實現業務類的介面
*/

public class ProxySubject implements Subject {
private Subject iSubject;//委託類
public ProxySubject(Subject subject){
//關鍵:關聯委託類
this.iSubject = subject;
}
@Override
public void visit() {
//呼叫真實業務類的方法
iSubject.visit();
}
}
public class Client {
public static void main(String[] args){
//構造一個真實主題物件
RealSubject realSubject = new RealSubject();
//通過真實主題物件構造一個代理物件
ProxySubject proxySubject = new ProxySubject(realSubject);
//呼叫代理類的相關方法
proxySubject.visit();
}
}
複製程式碼

其實可以看個幾個關鍵點:

  • 代理類和委託類公共實現同一個介面。(其實我覺得這個不是必然的。代理類可以不實現介面。而委託類實現介面是基於面向介面程式設計這個原則,實現介面使程式設計更加靈活而已)
  • 這個是核心:就是代理類構建例項需要關聯委託類。這樣才能呼叫代理方法,實則是呼叫委託類的方法實現功能。

其實靜態代理:在實際中不方便直接構建委託物件,而需要代理類實現具體的方法。

  • 動態代理
public interface DynamicInterface {
//實現邏輯
void implement();
}
/**
委託類
* 實現介面
*/

public class DynamicRealSubject implements DynamicInterface{
@Override
public void implement() {
Log.e("DynamicRealSubject","DynamicRealSubject___動態代理模式");
}
}
/**
* 實現InvocationHandler的類是執行時將生成的代理類需要完成的具體任務即invoke方法裡面
* 動態代理
*/

public class DynamicProxySubject implements InvocationHandler{
private Object sub;//需要被代理的物件
public DynamicProxySubject(Object sub){
this.sub = sub;
}
public DynamicProxySubject(){}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
Log.e("DynamicProxySubject","動態代理前");
//真正被代理類的方法被呼叫 method就是被代理的類的方法
method.invoke(sub,args);
//proxy這個引數在方法裡寫會記憶體溢位
// method.invoke(proxy,args);
Log.e("DynamicProxySubject","動態代理後");
return null;
}
}
//實現結果
public static void main(String[] args) throws Exception {
DynamicRealSubject realSubject = new DynamicRealSubject();
InvocationHandler handler = new DynamicProxySubject(realSubject);
//一次性生成
DynamicInterface subject = (DynamicInterface)Proxy
.newProxyInstance(cls.getClassLoader(),cls.getInterfaces(),handler);
//實現動態代理被代理類的方法
subject.implement();
}
複製程式碼
  • java JDK就提供了實現動態代理的方法。涉及到兩個類:
    1、InvocationHandler 實現委託類的方法的一個介面
    2、Proxy 代理類

動態代理與靜態代理最大的不同就是代理類非程式設計師預先定義好,而是在執行時才生成代理類。

提示:
我開始時候以為實現InvocationHandler介面的就是代理類,其實是錯誤的。該類其實提供給Proxy類構造時關聯用到的。每當生成代理類例項呼叫代理方法就會呼叫實現InvocationHandler介面的類中的invoke方法。

實現InvocationHandler介面的類

  • 這裡建構函式需要關聯一下委託類。目的就是在invoke方法裡面通過反射呼叫委託類的方法,其實實現的目的與靜態類是一致的。
  • invoke有三個引數 Object這個是代理類。Method 就是通過Proxy生成例項介面裡面的方法。而args陣列就是method的引數

看看這個InvocationHandler類到底如何與Proxy有聯絡的

DynamicRealSubject realSubject = new DynamicRealSubject();
InvocationHandler handler = new DynamicProxySubject(realSubject);
Class cls = realSubject.getClass();
DynamicInterface subject =
(DynamicInterface)Proxy.newProxyInstance(cls.getClassLoader(),cls.getInterfaces(),handler);
複製程式碼

這樣就將InvocationHandler類與Proxy類關聯起來。
看看Proxy.newProxyInstance這個方法是做什麼的

newProxyInstance方法內部

看到了cl這個變數明顯就是一個類物件然後在生成建構函式再構建物件。構建物件時通過h即InvocationHandler這個例項關聯一起。整個過程就是這樣生成一個代理例項。

看看getProxyClass0方法生成類物件
Paste_Image.png

由於該方法太長擷取關鍵部分:
這裡的generateProxy就是生成類物件,之前的程式碼是進行快取。

看看生成代理物件那程式碼:

Paste_Image.png

Paste_Image.png

生成代理物件時,把InvocationHandler例項傳進去
所以它最終生成的代理類是會有InvocationHandler的痕跡的。這裡我看了網上的說,生成的代理類是繼承Proxy實現委託介面。在代理方法裡面InvocationHandler通過反射呼叫invoke方法。

相關文章