Java代理模式

Java代理模式

    代理可以分爲:靜態代理(StaticProxy)和動態代理(DynamicProxy)。

代理概念

    爲某個對象提供一個代理,以控制這個對象的訪問。代理類和委託類有共同的父類和父接口,這樣在任何使用委託類對象的地方都可以使用代理對象代替。代理類負責請求的預處理、過濾、將請求分派給委託類處理以及委託類執行完請求後後的後續處理。代理分爲了靜態代理動態代理

    個人感覺代理這種模式汲取了繼承和組合的優點,即沒有暴露委託類的任何敏感信息,又能通過運用組合來實現較多的功能。至於委託類和代理類實現共同的接口(也就是所謂的代理接口),目的是爲了讓用戶用起來覺得根本不存在中間的代理類。(就好像一些中介機構做的很隱蔽,讓用戶和主人之間感覺沒有第三方一樣)。

靜態代理

    圖解中的Client即調用接口的一方,代理接口(Subject)、委託類(RealSubject)、代理類(ProxySubject),通過代理類來和用戶交流。下面用一個小故事來說明代理模式:A君有一套房子需要出售,由於買家不好找就直接掛在了B君的代售公司,過一段時間買家C君直接就把房子買走了。看下面的代碼實現:

interface sell {
public void sellHouse();
}

class PersonA implements sell{

public void sellHouse() {
    System.out.println("RealSubject...SellHouse...");
}
}

class PersonB implements sell{

//代理君B持有一個真實類(房主A)的實例,可以想象類似成留了一個電話號碼,有人來買房子就立馬通知
PersonA a = new PersonA();

public void sellHouse() {
    //有人來買房就立馬通知真實類(房主A)...
    a.sellHouse();
    System.out.println("Proxy...SellHouse...");
}
}

public class JavaTest{
public static void main(String[] args) {
    //我就相當於是買房子的C君
    PersonB b = new PersonB();
    //我直接找代理B君買房子
    b.sellHouse();
}
}

運行結果爲:
RealSubject...SellHouse...
Proxy...SellHouse...

    至於真實類和代理類需要實現同樣的一個接口,小達認爲統一接口能讓客戶端在用到真實類對象的地方都能夠替換成代理類,不用改變其調用的方法。因爲在這裏調用類完全不可以實現接口,利用組合的特性持有真實類的對象,通過自定義幾個方法直接調用真實類的方法,這樣暴露給外界的接口即是代理類自定義的一些接口了。

動態代理

    JDK 5中引入的動態代理機制,允許開發人員在運行時刻動態的創建出代理類及其對象。在運行時刻,可以動態的創建出一個實現了多個接口的代理類。

    說道動態代理,就不得不涉及到java.lang.reflect.Proxy類,這是Java動態代理機制生成的所有動態代理類的父類,它提供了一組靜態方法來爲一組接口動態的生成代理類及其對象。

    每個代理類的對象都會關聯一個表示內部處理邏輯的InvocationHandler接口的實現。使用者調用了代理對象所代理的接口中的方法的時候,這個調用的信息會被傳遞給InvocationHandlerinvoke方法。在invoke方法的參數中可以獲取到代理對象、方法對應的Method的對象和調用的實際參數,最後invoke方法執行的結果將被返回給調用者。這種做法實際上是對方法調用的攔截。

    簡單的來說,真實類在運行之前都不知道自己的代理類是誰,在運行期間通過反射來動態的生成一個代理類併爲真實類做代理。下面又有個小故事(純屬虛構,小朋友們不要學壞…..)來輔助理解:A君(真實類)馬上要考試了,但自己實力不夠,於是想找人代考(即找自己的代理類,在找到之前不知道自己的代理類是誰),接着通過B君(相當於InvocationHandler,用於分發調用請求)的介紹,找到了一隻學霸君(相當於動態生成的代理類,並不知道是誰)幫助代考。實現的代碼如下:

interface Exam {
public void findHelp();
}

class PersonA implements Exam{
public void findHelp() {
    System.out.println("PersonA...find...help...");
}
}

/**
* 這個類就相當於是B君,爲A君動態的創建代理類對象
*/
class MyInvocationHandler implements InvocationHandler {

private Object targetObject;

public Object newProxyInstance(Object o) {

    //targetObject是真實類的對象,就相當於是A君
    targetObject = o;

    /*
     * 在這裏動態的爲傳入的真實對象o動態的創建了一個代理類,也就是我們說的學霸君
     * 最後一個參數this指的是處理調用攔截的Handler
     */
    return Proxy.newProxyInstance(
            targetObject.getClass().getClassLoader(), 
            targetObject.getClass().getInterfaces(), 
            this);
}

/**
 * 在調用的時候攔截調用方法,然後做相的處理
 */
@Override
public Object invoke(Object proxy, Method method, Object[] args)
        throws Throwable {
    return method.invoke(targetObject, args);
}

}
public class JavaTest{
public static void main(String[] args) {
    PersonA a = new PersonA();
    MyInvocationHandler mih = new MyInvocationHandler();
    //爲A君動態生成代理類
    Exam e = (Exam) mih.newProxyInstance(a);
    e.findHelp();
}
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章