java 動態代理

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();

    }

 

 

  客戶端調用:

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,由它接管實際的工作。

 

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

 

 

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

 

public   interface  Subject  {

    abstract   public   void  request();

 

 

 

具體角色RealSubject:

public   class  RealSubject  implements  Subject {

 

   public  RealSubject() {}

 

   public   void  request() {

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

  }

 

 

 

代理處理器:

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();

 

    // 以下是一次性生成代理

   Subject subject  =  (Subject) Proxy.newProxyInstance(cls.getClassLoader(), cls.getInterfaces(),ds );

   subject.request();

 

 

程序運行結果:

before calling public abstract void Subject.request()

From real subject.

after calling public abstract void Subject.request()

 

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

http://zhidao.baidu.com/question/291144434.html
發佈了38 篇原創文章 · 獲贊 3 · 訪問量 18萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章