首頁 > Java > java教程 > 主體

Java中動態代理的實作教程

零下一度
發布: 2017-06-30 09:52:45
原創
1306 人瀏覽過

以下的內容部分參考了網路上的內容,在此對原作者表示感謝!  

        Java中動態代理程式的實現,關鍵是這兩個東西:Proxy、InvocationHandler,以下從InvocationHandler介面中的invoke方法入手,簡單說明Java如何實現動態代理的。  
        首先,invoke方法的完整形式如下: 

Java程式碼Java中動態代理的實作教程
  1. ##Java程式碼

  2. public Object invoke(Object proxy, Method method, Object[] args) 

    throws Throwable  
  3. #112     {  

        method.invoke(obj,        method.invoke(obj,        meth


##        return 
null;  

  
Java中動態代理的實作教程
    #        先猜測一下,method是呼叫的方法,也就是需要執行的方法;args是方法的參數; proxy,這個參數是什麼?以上invoke()方法的實作就是比較標準的形式,我們看到,這裡並沒有用到proxy參數。查看JDK文件中Proxy的說明,如下:
  1.  

Java程式碼  




A method invocation on a proxy instance through one of its proxy interfaces will be dispatchedo proxy instance, a java.lang.reflect.Method object identifying the method that was invoked, and an array of type Object containing the 
.
        因此可以知道以上的猜測是正確的,同時也知道,proxy參數傳遞的即是代理類別的實例。
 
        為了方便說明,這裡寫一個簡單的範例來實作動態代理。

 
       
Java中動態代理的實作教程
  1. #Java代碼

      
  2. Java代碼  

  3. //抽象角色(動態代理只能代理介面)  

  4. public 
  5. interface Subject {  

    public void request();
}  

Java中動態代理的實作教程
####################### ##########################################Java程式碼###  #### ########
  1. //真實角色:實作了Subject的request()方法  

  2. public #class RealSubject implements Subject{  

  3.     public void request(){

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

  5. }  

  6. }  


Java中動態代理的實作教程
  1. Java程式碼
  2.   
  3. //實作了InvocationHandler  
  4. public 

    class DynamicSubject 

    #implements  
  5. ##{  
  6.     private Object obj;//這是動態代理的好處,被封裝的物件是Object類型,接受任意型別的物件  

  7.     public DynamicSubject ()  

  8.     {  
  9.     }  
  10. ##>
  11. ##    
  12. public DynamicSubject(Object obj)  

  13.     {  
  14.  ;  

  15.     }  

  16. ##    

    //這個方法不是我們所顯示的去呼叫  
  17.     
  18. public Object invoke(Object proxy, Method method, Object[]  ) ##oo

  19. #    {  

#        System.out.println("before cal#  +#1method); ##        method.invoke(obj, args);  //----->這一步詳看下一篇文章,java 以反射機制呼叫某個類別的方法,看完你會了解的。
        System.out.println(

"after calling " + method);  
Java中動態代理的實作教程
###        ###return ###null;  ###################   ####################}  ##################################################################################### ############################################Java程式碼###  ## ##########
  1. //用戶端:產生代理實例,並且呼叫了request()方法  

  2. public 

  3. ## class Client {  
  4.     public static #void main(String[] args) throws Throwable{  

  5.         
  6. #// TOf

  7. ##        Subject rs=new RealSubject();//這裡指定被代理類  

  8.         InvocationHandler ds=new DynamicSubject(rs);  

  9.    
  10. ##        //以下為一次產生代理程式  

  11. ##        Subject subject=(Subject) Proxy.newProxyInstance(  

    ##   ds);  
  12.         //這裡可以透過運作結果證明subject是Proxy的一個實例,這個實例實現了Subject介面  

  13. ##        System.out.println(subject instanceof Proxy);  

  14.         //這裡可以看出subject的Class類別是$Proxy0,這個$Proxy0類別繼承了Proxy,實作了Subject介面  

  15. ## println(

    "subject的Class類別是:"+subject.getClass().toString());  

  16. #        System.out.print(
  17. "subject中的屬性有:");  

  18. ##  ] field=subject.getClass().getDeclaredFields();  

            for(Field f:field){  

  19.             System.out.print(f.getName()+
  20. ", ");  
  21. ##  

  22. ##        System.out.print(
  23. "\n"+

    "subject中的方法有:");  

  24. ##        Method[] method=subject.getClass().getDeclaredMethods();  

  25.         
  26. for(Method m:method){  

    ###          ");  ###############        }  ########################   ##"\n"+###"subject的父類別是:"+subject.getClass().getSuperclass());  ############################# ##########        System.out.print(###"\n"+###"subject實作的介面是:");  ############################################################################################ #################        Class>[] interfaces=subject.getClass().getInterfaces();  ############## ##########        ###for(Class> i:interfaces){  ################    )+###", ");  ########
  27.         }  

  28.         System.out. "運作結果為:");  

  29.         subject.request();  

  30.  
  31. #}  


Java中動態代理的實作教程
  1. Xml程式碼
  2.   
  3. 運行結果如下:此處省略了包名,***取代  
  4. #true  
  5. subject的Class類別是:class $Proxy0  
  6. subject中的屬性有:m1, m3, m0, m2,   
  7. subject中的方法方法有:request, hashCode, equals, toString,   
  8. subject的父類是:class java.lang.reflect.Proxy  
  9. subject實現的介面是:cn.edu.ustc.dynamicproxy.Subject,   
  10. 運作結果為:  
運作結果為:  

#before calling public abstract void ***.Subject.request()  From real subject.  

fter void ***.Subject.request()  




PS:這個結果的訊息非常重要,至少對我來說。因為我在動態代理犯暈的根源就在於將上面的subject.request()理解錯了,至少是被表面所迷惑,沒有發現這個subject和Proxy之間的聯繫,一度糾結於最後調用的這個request( )是怎麼跟invoke()聯絡上的,而invoke又是怎麼知道request存在的。其實上面的true和class $Proxy0就能解決很多的疑問,再加上下面將要說的$Proxy0的源碼,完全可以解決動態代理的疑惑了。

 
        從上述程式碼和結果可以看出,我們並沒有顯示的呼叫invoke()方法,但是這個方法確實執行了。下面就整個的過程進行分析一下:
 Java中動態代理的實作教程        從Client中的程式碼來看,可以從newProxyInstance這個方法作為突破口,我們先來看Proxy類別中newProxyInstance方法的原始程式碼:
#######################################Java程式碼### ############
  1. public static Object newProxyInstance(ClassLoader loader,  

  2. ##      ,

  3.         IncallingHandler h)  

  4. #拋出IllegalArgumentException  

  5. #{  

  6.     if (h == null) {  

  7.  ##   

    new空指標異常();  

  8.     }  
  9. ##    
  10. /*

  11.      * 尋找或產生指定的代理類別。 

  12.      */  

  13. #    類 cl = getProxyClass(loader, 介面);  
  14.     
  15. /* 

  16. ##     * 則呼叫其具有指定呼叫處理程序的建構子。 ##########
  17. ##           

    /* 

  18.          

    Proxy
  19. ##            * private final static Class[] constructorParams = { InitationHandler.class }; 
  20.             * 缺點即形參為IncallingHandler類型的建構方法 
  21.  

  22.         建構函式cons = cl.getConstructor(constructorParams);  

  23.         
  24. #return (Object) cons.newInstance(

    new Object[] { h });  

  25.     } catch (NoSuchMethodException e) {  

  26. #   ##新的內部錯誤(e.toString());  

  27.     } 

    catch (IllegalAccessException e) {  
  28. #   ##新的內部錯誤(e.toString());  

  29.     } catch (InstantiationException e) {  

  30. ##o ##   ##新的內部錯誤(e.toString());  
  31.     } 

    catch (InitationTargetException e) {  
  32. ##    ##新的內部錯誤(e.toString());  

  33.     }  

    }  
  34. ##



            Proxy.newProxyInstance(ClassLoader loader, Class>Class>Class> ;[] interfaces, InvocationHandler h)做了以下幾件事.
           (1)根據參數loader和interfaces調用方法getProxyClass(loader, interfaces)創建代理類$Proxy0.$Profaces調用類實現了interfaces的接口,並並繼承了Proxy類別. 
           (2)實例化$Proxy0並在建構方法中把DynamicSubject傳過去,接著$Proxy0呼叫父類別Proxy的建構器,為h賦值,如下: 

    #Java代碼Java中動態代理的實作教程  
    1. #class Proxy{  

    2. #    InvocationHandler h=null;  

    3.     protected Proxy(InvocationHandler h) {  

    4.  = h;  

    5. #    }  

    6.     ...  

    7. ##    ...  

      }
    o

    #'


            來看看這個繼承了Proxy的$Proxy0的原始碼:
     

    Java中動態代理的實作教程
    ##################################################################################### #########################Java程式碼###  ############
    1. public final class $Proxy0 extends Proxy implements Subject {  

    2. #11 #    private 

      static 方法m1;  
    3.     private 

      static 方法 m0;  
    4.     

      private static 方法 m3;  

    5.     

      private static 方法 m2;  ##########靜止的{###### # try {  

    6. ##            m1 = Class.forName(
    7. "java.

    8. ##                    

      Fnew Class[] { Class.forName("java.lang.Object"#new Class[] { Class.forName("java.lang.Object"#new Class);  

    9.             m0 = Class.forName(

      "java.lang.Object").getMethod(
    10. "hashCode",  
    11. #                  地  

    12.             m3 = Class.forName(

      "***.RealSubject").getMethod(
    13. "請求",  
    14.                     
    15. new Class[

      0]);  

    16.             m2 = Class.forName(
    17. "java.lang.Object").getMethod(

      "toString",  

    18.                     

      new Class[
    19. 0]);  
    20.         } 

      catch (NoSuchMethodException nosuchmeth
    21. #            
    22. 以拋出 

      new NoSuchMethodError(nosuchmethodException.getMessage());  

    23.         } 
    24. catch (ClassNotFoundException classnotfoundException) {  

       新的 NoClassDefFoundError(classnotfoundException.getMessage());  ###########//靜止的#### #

    25. ##    public $Proxy0(InitationHandler incallinghandler) {  ##     

    26.     }  

      ##################    ###@Override  ########    ###@Override ##########    ###public ###final ###boolean equals(Object obj) {  ###############  ##試{ ######
    27.             return ((Boolean) super.h.invoke(this, m1, new Object[] { obj })) .booleanValue();  

    28.         } catch (Throwable throwable) {  

    29.             throw new UndeclaredThrowableException(throwable);  

    30.         }  

    31.     }  

    32.     @Override  

    33.     public final int hashCode() {  

    34.         try {  

    35.             return ((Integer) super.h.invoke(this, m0, null)).intValue();  

    36.         } catch (Throwable throwable) {  

    37.             throw new UndeclaredThrowableException(throwable);  

    38.         }  

    39.     }  

    40.     public final void request() {  

    41.         try {  

    42.             super.h.invoke(this, m3, null);  

    43.             return;  

    44.         } catch (Error e) {  

    45.         } catch (Throwable throwable) {  

    46.             throw new UndeclaredThrowableException(throwable);  

    47.         }  

    48.     }  

    49.     @Override  

    50.     public final String toString() {  

    51.         try {  

    52.             return (String) super.h.invoke(this, m2, null);  

    53.         } catch (Throwable throwable) {  

    54.             throw new UndeclaredThrowableException(throwable);  

    55.         }  

    56.     }  

    57. }  


    The Proxy0 instance is cast to Subject and the reference is assigned to subject. When the subject.request() method is executed, the request() method in the $Proxy0 class is called, and then the invoke() method of h in the parent class Proxy is called. That is, InvocationHandler.invoke().

    PS: 1. One thing that needs to be explained is that the getProxyClass method in the Proxy class returns the Proxy Class class. The reason why I explain this is because I made a low-level mistake at the beginning, thinking that what was returned was the "Class of the proxied class" - -! It is recommended to take a look at the source code of getProxyClass, it is very long =. =
    2. It can be seen from the source code of $Proxy0 that the dynamic proxy class not only proxies the methods in the explicitly defined interface, but also proxies the inherited equals() in the java root class Object. , hashcode(), toString(), and only these three methods.

    Q: So far, there is still a question. The first parameter in the invoke method is an instance of Proxy (to be precise, the instance of $Proxy0 is ultimately used), but what? What to use? In other words, how does the program show its effect?
    A: From my current level, this proxy parameter has no effect. In the entire dynamic proxy mechanism, the proxy parameter of the invoke method in InvocationHandler is not used. The parameter passed in is actually an instance of the proxy class. I think it may be to allow programmers to use reflection in the invoke method to obtain some information about the proxy class.
    #

以上是Java中動態代理的實作教程的詳細內容。更多資訊請關注PHP中文網其他相關文章!

相關標籤:
來源:php.cn
本網站聲明
本文內容由網友自願投稿,版權歸原作者所有。本站不承擔相應的法律責任。如發現涉嫌抄襲或侵權的內容,請聯絡admin@php.cn
熱門教學
更多>
最新下載
更多>
網站特效
網站源碼
網站素材
前端模板
關於我們 免責聲明 Sitemap
PHP中文網:公益線上PHP培訓,幫助PHP學習者快速成長!