標籤:java代理模式 java設計模式 java代理 proxy 動態代理
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介面的實現。使用者調用了代理對象所代理的介面中的方法的時候,這個調用的資訊會被傳遞給InvocationHandler的invoke方法。在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);}/** * 在調用的時候攔截調用方法,然後做相的處理 */@Overridepublic 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();}}
Java代理模式