Java代理模式及動態代理類

          1. ????? 代理模式

          代理模式的作用是:為其他對象提供一種代理以控制對這個對象的訪問。在某些情況下,一個客戶不想或者不能直接引用另一個對象,而代理對象可以在客戶端和目標對象之間起到中介的作用。

          代理模式一般涉及到的角色有:

          抽象角色 :聲明真實對象和代理對象的共同接口;

          代理角色 :代理對象角色內部含有對真實對象的引用,從而可以操作真實對象,同時代理對象提供與真實對象相同的接口以便在任何時刻都能代替真實對象。同時,代理對象可以在執行真實對象操作時,附加其他的操作,相當于對真實對象進行封裝。

          真實角色 :代理角色所代表的真實對象,是我們最終要引用的對象。 ( 參見文獻 1)

          以下以《 Java 與模式》中的示例為例:

          抽象角色:

          abstract public class Subject

          {

          ??? abstract public void request();

          }

          真實角色:實現了 Subject request() 方法。

          public class RealSubject extends Subject

          {

          ?????? public RealSubject()

          ?????? {

          ?????? }

          ??????

          ?????? public void request()

          ?????? {

          ?????? ?????? System.out.println("From real subject.");

          ?????? }

          }

          代理角色:

          public class ProxySubject extends Subject

          {

          ??? private RealSubject realSubject;? // 以真實角色作為代理角色的屬性

          ??????

          ?????? public ProxySubject()

          ?????? {

          ?????? }

          ?

          ?????? public void request()? // 該方法封裝了真實對象的 request 方法

          ?????? {

          ??????? preRequest();?

          ?????? ?????? if( realSubject == null )

          ??????? {

          ????????????? ?????? realSubject = new RealSubject();

          ????????????? }

          ??????? realSubject.request();? // 此處執行真實對象的 request 方法

          ??????? postRequest();

          ?????? }

          ?

          ??? private void preRequest()

          ??? {

          ??????? //something you want to do before requesting

          ??? }

          ?

          ??? private void postRequest()

          ??? {

          ??????? //something you want to do after requesting

          ??? }

          }

          客戶端調用:

          Subject sub=new ProxySubject();

          Sub.request();

          ?????? 由以上代碼可以看出,客戶實際需要調用的是 RealSubject 類的 request() 方法,現在用 ProxySubject 來代理 RealSubject 類,同樣達到目的,同時還封裝了其他方法 (preRequest(),postRequest()) ,可以處理一些其他問題。

          ?????? 另外,如果要按照上述的方法使用代理模式,那么真實角色必須是事先已經存在的,并將其作為代理對象的內部屬性。但是實際使用時,一個真實角色必須對應一個代理角色,如果大量使用會導致類的急劇膨脹;此外,如果事先并不知道真實角色,該如何使用代理呢?這個問題可以通過 Java 的動態代理類來解決。

          ?

          2. 動態代理類

          ?????? Java 動態代理類位于 Java.lang.reflect 包下,一般主要涉及到以下兩個類:

          (1). Interface InvocationHandler :該接口中僅定義了一個方法 Object invoke(Object obj,Method method, Object[]?args) 。在實際使用時,第一個參數 obj 一般是指代理類, method 是被代理的方法,如上例中的 request() args 為該方法的參數數組。這個抽象方法在代理類中動態實現。


          (2).Proxy
          :該類即為動態代理類,作用類似于上例中的 ProxySubject ,其中主要包含以下內容:

          Protected Proxy(InvocationHandler h) :構造函數,估計用于給內部的 h 賦值。

          Static Class getProxyClass (ClassLoader?loader, Class[]?interfaces) :獲得一個代理類,其中 loader 是類裝載器, interfaces 是真實類所擁有的全部接口的數組。

          Static Object newProxyInstance(ClassLoader?loader, Class[]?interfaces, InvocationHandler?h) :返回代理類的一個實例,返回后的代理類可以當作被代理類使用 ( 可使用被代理類的在 Subject 接口中聲明過的方法 )


          ??????
          所謂 Dynamic Proxy 是這樣一種 class :它是在運行時生成的 class ,在生成它時你必須提供一組 interface 給它,然后該 class 就宣稱它實現了這些 interface 。你當然可以把該 class 的實例當作這些 interface 中的任何一個來用。當然啦,這個 Dynamic Proxy 其實就是一個 Proxy ,它不會替你作實質性的工作,在生成它的實例時你必須提供一個 handler ,由它接管實際的工作。 ( 參見文獻 3)

          ??? 在使用動態代理類時,我們必須實現 InvocationHandler 接口,以第一節中的示例為例:

          抽象角色 ( 之前是抽象類,此處應改為接口 )

          public interface Subject

          {

          ??? abstract public void request();

          }

          具體角色 RealSubject :同上;

          ?

          代理角色:

          import java.lang.reflect.Method;

          import java.lang.reflect.InvocationHandler;

          ?

          public class DynamicSubject implements InvocationHandler {

          ? private Object sub;

          ?

          ? public DynamicSubject() {

          ? }

          ?

          ? public DynamicSubject(Object obj) {

          ??? sub = obj;

          ? }

          ?

          ?

          ? public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {

          ??? System.out.println("before calling " + method);

          ?

          ??? method.invoke(sub,args);

          ?

          ??? System.out.println("after calling " + method);

          ??? return null;

          ? }

          ?

          }

          ?

          ?????? 該代理類的內部屬性為 Object 類,實際使用時通過該類的構造函數 DynamicSubject(Object obj) 對其賦值;此外,在該類還實現了 invoke 方法,該方法中的

          method.invoke(sub,args);

          其實就是調用被代理對象的將要被執行的方法,方法參數 sub 是實際的被代理對象, args 為執行被代理對象相應操作所需的參數。通過動態代理類,我們可以在調用之前或之后執行一些相關操作。

          客戶端

          import java.lang.reflect.InvocationHandler;

          import java.lang.reflect.Proxy;

          import java.lang.reflect.Constructor;

          import java.lang.reflect.Method;

          ?

          public class Client

          {

          ?

          ??? static public void main(String[] args) throws Throwable

          ?????? {

          ????? RealSubject rs = new RealSubject();? // 在這里指定被代理類

          ????? InvocationHandler ds = new DynamicSubject(rs);? // 初始化代理類

          ?????? ? Class cls = rs.getClass();

          ????? // 以下是分解步驟

          ????? /*

          ???? ?Class c = Proxy.getProxyClass(cls.getClassLoader(),cls.getInterfaces()) ;

          ???? ?Constructor ct=c.getConstructor(new Class[]{InvocationHandler.class});

          ???? ?Subject subject =(Subject) ct.newInstance(new Object[]{ds});

          ???? */

          ???? // 以下是一次性生成

          ????? Subject subject = (Subject) Proxy.newProxyInstance(cls.getClassLoader(),

          ???????????????????????????????? cls.getInterfaces(),ds );


          ????? subject.request();

          }

          ?????? 通過這種方式,被代理的對象 (RealSubject) 可以在運行時動態改變,需要控制的接口 (Subject 接口 ) 可以在運行時改變,控制的方式 (DynamicSubject ) 也可以動態改變,從而實現了非常靈活的動態代理關系 ( 參見文獻 2)

          posted on 2010-01-17 16:52 飛熊 閱讀(243) 評論(0)  編輯  收藏 所屬分類: java設計模式

          <2010年1月>
          272829303112
          3456789
          10111213141516
          17181920212223
          24252627282930
          31123456

          導航

          統計

          常用鏈接

          留言簿(1)

          隨筆分類

          隨筆檔案

          文章分類

          文章檔案

          收藏夾

          搜索

          最新評論

          閱讀排行榜

          評論排行榜

          主站蜘蛛池模板: 北海市| 汽车| 洛扎县| 仁怀市| 大渡口区| 伽师县| 鸡泽县| 图们市| 宝坻区| 淳化县| 惠安县| 建水县| 榆中县| 湟源县| 黄大仙区| 东明县| 沐川县| 三穗县| 柳州市| 肇庆市| 建瓯市| 鄢陵县| 田阳县| 东方市| 西林县| 广丰县| 阳高县| 蒙自县| 颍上县| 固阳县| 水富县| 江源县| 出国| 玛多县| 泸州市| 通道| 方正县| 鹿邑县| 页游| 阳原县| 寿阳县|