搜尋
首頁Javajava教程Java中動態代理的實作教程

Java中動態代理的實作教程

Jun 30, 2017 am 09:52 AM
invoke問題

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

        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中文網其他相關文章!

陳述
本文內容由網友自願投稿,版權歸原作者所有。本站不承擔相應的法律責任。如發現涉嫌抄襲或侵權的內容,請聯絡admin@php.cn
如何將Maven或Gradle用於高級Java項目管理,構建自動化和依賴性解決方案?如何將Maven或Gradle用於高級Java項目管理,構建自動化和依賴性解決方案?Mar 17, 2025 pm 05:46 PM

本文討論了使用Maven和Gradle進行Java項目管理,構建自動化和依賴性解決方案,以比較其方法和優化策略。

如何使用適當的版本控制和依賴項管理創建和使用自定義Java庫(JAR文件)?如何使用適當的版本控制和依賴項管理創建和使用自定義Java庫(JAR文件)?Mar 17, 2025 pm 05:45 PM

本文使用Maven和Gradle之類的工具討論了具有適當的版本控制和依賴關係管理的自定義Java庫(JAR文件)的創建和使用。

如何使用咖啡因或Guava Cache等庫在Java應用程序中實現多層緩存?如何使用咖啡因或Guava Cache等庫在Java應用程序中實現多層緩存?Mar 17, 2025 pm 05:44 PM

本文討論了使用咖啡因和Guava緩存在Java中實施多層緩存以提高應用程序性能。它涵蓋設置,集成和績效優勢,以及配置和驅逐政策管理最佳PRA

如何將JPA(Java持久性API)用於具有高級功能(例如緩存和懶惰加載)的對象相關映射?如何將JPA(Java持久性API)用於具有高級功能(例如緩存和懶惰加載)的對象相關映射?Mar 17, 2025 pm 05:43 PM

本文討論了使用JPA進行對象相關映射,並具有高級功能,例如緩存和懶惰加載。它涵蓋了設置,實體映射和優化性能的最佳實踐,同時突出潛在的陷阱。[159個字符]

Java的類負載機制如何起作用,包括不同的類載荷及其委託模型?Java的類負載機制如何起作用,包括不同的類載荷及其委託模型?Mar 17, 2025 pm 05:35 PM

Java的類上載涉及使用帶有引導,擴展程序和應用程序類負載器的分層系統加載,鏈接和初始化類。父代授權模型確保首先加載核心類別,從而影響自定義類LOA

See all articles

熱AI工具

Undresser.AI Undress

Undresser.AI Undress

人工智慧驅動的應用程序,用於創建逼真的裸體照片

AI Clothes Remover

AI Clothes Remover

用於從照片中去除衣服的線上人工智慧工具。

Undress AI Tool

Undress AI Tool

免費脫衣圖片

Clothoff.io

Clothoff.io

AI脫衣器

AI Hentai Generator

AI Hentai Generator

免費產生 AI 無盡。

熱門文章

R.E.P.O.能量晶體解釋及其做什麼(黃色晶體)
4 週前By尊渡假赌尊渡假赌尊渡假赌
R.E.P.O.最佳圖形設置
4 週前By尊渡假赌尊渡假赌尊渡假赌
R.E.P.O.如果您聽不到任何人,如何修復音頻
4 週前By尊渡假赌尊渡假赌尊渡假赌
R.E.P.O.聊天命令以及如何使用它們
4 週前By尊渡假赌尊渡假赌尊渡假赌

熱工具

VSCode Windows 64位元 下載

VSCode Windows 64位元 下載

微軟推出的免費、功能強大的一款IDE編輯器

DVWA

DVWA

Damn Vulnerable Web App (DVWA) 是一個PHP/MySQL的Web應用程序,非常容易受到攻擊。它的主要目標是成為安全專業人員在合法環境中測試自己的技能和工具的輔助工具,幫助Web開發人員更好地理解保護網路應用程式的過程,並幫助教師/學生在課堂環境中教授/學習Web應用程式安全性。 DVWA的目標是透過簡單直接的介面練習一些最常見的Web漏洞,難度各不相同。請注意,該軟體中

SublimeText3 Linux新版

SublimeText3 Linux新版

SublimeText3 Linux最新版

Dreamweaver CS6

Dreamweaver CS6

視覺化網頁開發工具

MantisBT

MantisBT

Mantis是一個易於部署的基於Web的缺陷追蹤工具,用於幫助產品缺陷追蹤。它需要PHP、MySQL和一個Web伺服器。請查看我們的演示和託管服務。