Heim  >  Artikel  >  Java  >  Tutorial zur Implementierung eines dynamischen Proxys in Java

Tutorial zur Implementierung eines dynamischen Proxys in Java

零下一度
零下一度Original
2017-06-30 09:52:451261Durchsuche

Der folgende Inhalt basiert teilweise auf Inhalten im Internet. Ich möchte dem ursprünglichen Autor meinen Dank aussprechen!

Der Schlüssel zur Implementierung eines dynamischen Proxys in Java sind diese beiden Dinge: Proxy und InvocationHandler. Beginnen wir mit der Aufrufmethode in der InvocationHandler-Schnittstelle und erklären kurz, wie Java einen dynamischen Proxy implementiert.
Zunächst lautet die vollständige Form der Aufrufmethode wie folgt:

Java Code Tutorial zur Implementierung eines dynamischen Proxys in Java
  1. public Object invoke(Object Proxy, Method method, Object[] args) throws Throwable

  2. 🎜>

  3.                                                                   >
  4. Die Methode ist die aufgerufene Methode, also die Methode, die ausgeführt werden muss. Argumente sind die Parameter der Methode. Was ist dieser Parameter? Die obige Implementierung der invoke()-Methode ist eine relativ Standardform. Wir sehen, dass der Proxy-Parameter hier nicht verwendet wird. Sehen Sie sich die Beschreibung von Proxy in der JDK-Dokumentation wie folgt an:

  5. Java-Code


Ein Methodenaufruf auf einer Proxy-Instanz über eine ihrer Proxy-Schnittstellen wird an die Aufrufmethode des Aufruf-Handlers der Instanz weitergeleitet und übergibt die Proxy-Instanz, ein java.lang.reflect.Method-Objekt, das die aufgerufene Methode identifiziert, und ein Array vom Typ Object, das die Argumente enthält
Daraus können wir erkennen, dass die obige Vermutung richtig ist, und wir wissen auch, dass der Proxy-Parameter an eine Instanz der Proxy-Klasse übergeben wird.
Der Einfachheit halber finden Sie hier ein einfaches Beispiel für die Implementierung eines dynamischen Proxys.

Tutorial zur Implementierung eines dynamischen Proxys in Java
  1. Java-Code


//Abstrakte Rolle (dynamischer Proxy kann nur Proxy-Schnittstellen)



public
interface Subject {

public Tutorial zur Implementierung eines dynamischen Proxys in Javavoid request();
  1. Java-Code
  1. //Echte Rolle: Implementierte die request()-Methode des Subjekts

  2. öffentliche Klasse RealSubject implementiert Subject{

  3. public void request(){

  4. System.out.println("Aus echtem Betreff."

  5. }

  6. }

Java-Code

//Implementiert InvocationHandler
Tutorial zur Implementierung eines dynamischen Proxys in Javapublic
class DynamicSubject
implements InvocationHandler
  1. {
  2. private Object obj ;//Dies ist ein dynamischer Proxy. Vorteile: Das gekapselte Objekt ist vom Typ Objekt und akzeptiert jeden Objekttyp

  3. public DynamicSubject () 

  4.                                             🎜>
  5.  

    public DynamicSubject(Object. obj ) 

  6.  { 

  7.                                   ; 

  8.                                                                  Explizite Aufforderung

  9. public Object invoke(Object Proxy, Method method, Object[] args)
  10. throws Throwable

  11. {

  12. System.out.println(

    "vor dem Aufruf " + method); 🎜>

  13. method.invoke(obj, args); //-----> Bitte lesen Sie den nächsten Artikel für Details zu diesem Schritt. Java ruft eine bestimmte Funktion über den Reflexionsmechanismus auf. Nachdem Sie sie gelesen haben, werden Sie die Methoden jeder Klasse verstehen.

  14. System.out.println(

    "nach Aufruf " + Methode);

  15.                                                                                       🎜 >

  16. Java-Code

    1. //Client: hat eine Proxy-Instanz generiert und die request()-Methode

    2. public class aufgerufen Client {

    3. public static void main(String[] args ) wirft Throwable{

    4. 🎜>

    5. Subject rs=

      new RealSubject();
    6. //Geben Sie hier die Proxy-Klasse an
    7. InvocationHandler ds=

      new DynamicSubject(rs );
    8. Klasse> cls=rs.getClass(); >

                                                                 🎜>> );
    9.                                                                               🎜>
    10. . out.println( Betreff

      Instanceof Proxy); ist $Proxy0. Diese $Proxy0-Klasse erbt Proxy und implementiert die Subject-Schnittstelle

    11. System.out(

      "Subject's Class-Klasse ist: "+subject.getClass ().toString());

    12. System.out.print(
    13. "Die Attribute im Betreff sind : ");
    14. Field[ ] field=subject.getClass().getDeclaredFields();
    15. > System.out.print(f.getName()+", "

    16. }
    17. System.out.print(

      "n"+"Die Methoden im Betreff sind: ");

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

    19.                                                               ) ; >"n"+

    20. System.out.print(
    21. "n"+
    22. "Die vom Betreff implementierte Schnittstelle ist: " ); ;

    23. for(Class> i:interfaces){
    24.   System.out.print(i.getName()+

      ", "

    25. }

    26. System.out.println("nn"+ „Das Operationsergebnis ist:“);

Xml-Code
Die laufenden Ergebnisse sind wie folgt: Der Paketname wird hier weggelassen, *** wird ersetzt durch
true

Subject's Class class Es ist: class $Proxy0
The Attribute im Betreff sind: m1, m3, m0, m2, Tutorial zur Implementierung eines dynamischen Proxys in Java
Die Methoden im Betreff sind: request , hashCode, equal, toString,
  1. Die übergeordnete Klasse des Subjekts ist: Klasse java.lang.reflect.Proxy
  2. Die von Subjekt implementierte Schnittstelle ist:cn.edu.ustc.dynamicproxy.Subject,  
  3. Das laufende Ergebnis ist:  
  4. vor dem Aufruf von public abstract void ***.Subject.request()
  5. Aus echtem Betreff
  6. nach Aufruf von public abstract void ** *.Subject.request()
  7. PS: Die Informationen in diesem Ergebnis sind sehr wichtig, zumindest für mich. Denn die Hauptursache für meine Verwirrung über den dynamischen Proxy ist, dass ich die obige subject.request() missverstanden habe. Zumindest war ich von der Oberfläche verwirrt, die ich beim letzten Aufruf festgestellt habe von request( ) ist mit invoke() verbunden und woher weiß invoke, dass eine Anfrage existiert? Tatsächlich können die oben genannten true- und $Proxy0-Klassen zusammen mit dem unten erwähnten Quellcode von $Proxy0 die Zweifel an dynamischen Proxys vollständig lösen.

  8. Wie Sie dem obigen Code und den Ergebnissen entnehmen können, haben wir die invoke()-Methode nicht explizit aufgerufen, diese Methode wurde jedoch tatsächlich ausgeführt. Lassen Sie uns den gesamten Prozess analysieren:
  9. Aus dem Code im Client können wir die newProxyInstance-Methode als Durchbruch verwenden. Schauen wir uns zunächst den Quellcode der newProxyInstance-Methode in der Proxy-Klasse an:





Java-Code


  1. öffentliches statisches Objekt newProxyInstance(ClassLoader Loader,  

  2.         Class>[] Schnittstellen,

  3.         InvocationHandler h)  

  4. throws IllegalArgumentException  

  5. {  

  6.     if (h == null) {  

  7.         throw neu NullPointerException();  

  8.     }  

  9.     /* 

  10.      * Suchen Sie die ausgewiesene Proxyklasse oder generieren Sie. 

  11.      */  

  12.     Class cl = getProxyClass(loader, interfaces);  

  13.     /* 

  14.      * Invoke its Konstruktor mit dem designierten Aufruf-Handler. 

  15.      */  

  16.     versuchen {  

  17.            /* 

  18.             * Proxy源码开始有这样的定义: 

  19.             * private final static Class[] constructorParams = { InvocationHandler.class }; 

  20.             * Nachteile           */

  21.         Constructor cons = cl.getConstructor(constructorParams);  

  22.         
  23. return (Object) cons.newInstance(

    new Object[] { h });  

  24.     } catch (NoSuchMethodException e) {  

  25.         throw  new InternalError(e.toString());  

  26.     } catch (IllegalAccessException e) {  

  27.         throw  new InternalError(e.toString());  

  28.     } catch (InstantiationException e) {  

  29.         throw  new InternalError(e.toString());  

  30.     } catch (InvocationTargetException e) {  

  31.         throw  new InternalError(e.toString());  

  32.     }  

  33. }  


  34. Proxy.newProxyInstance(ClassLoader Loader, Class> ; [] Interfaces, Invacationhandler H) Führen Sie Folgendes aus:
    (1) Rufen Sie die Methode getProxyClass (Loader, Interfaces) entsprechend dem Parameter Loader und Interfaces auf und erben Sie die Proxy-Klasse (2) Instanziieren Sie $Proxy0 und übergeben Sie DynamicSubject im Konstruktor. Dann ruft $Proxy0 den Konstruktor der übergeordneten Klasse Proxy auf und weist h wie folgt einen Wert zu:
    class Proxy{
    InvocationHandler h=
    null;

                                              = h; Tutorial zur Implementierung eines dynamischen Proxys in Java
    }
    1. ...

    2. Nehmen wir mal ein Schauen Sie sich den Quellcode von $Proxy0 an, der Proxy erbt:

    Java-Code

    1. öffentliche finale Klasse $Proxy0 erweitert Proxy implementiert Subject {  

    2.     private statische Methode m1;  

    3.     private statische Methode m0;  

    4.     privat statische Methode m3;  

    5.     privat statische Methode m2;  

    6.     statisch {  

    7. versuchen Sie {  

    8.             m1 = Class.forName("java.lang.Object").getMethod("equals",  

    9.                      new Class[] { Class.forName("java.lang.Object") });  

    10.             m0 = Class.forName("java.lang.Object").getMethod( "hashCode",  

    11.                     new Class[0]);  

    12.             m3 = Class.forName("***.RealSubject").getMethod( "Anfrage",  

    13.                     neue Klasse[0]);  

    14.             m2 = Class.forName("java.lang.Object").getMethod( "toString",  

    15.                     new Class[0]);  

    16.         } catch (NoSuchMethodException nosuchmethodeception) {  

    17.             throw new NoSuchMethodError(nosuchmethodeception.getMessage());  

    18.         } catch (ClassNotFoundException classnotfoundException) {  

    19.             throw  new NoClassDefFoundError(classnotfoundException.getMessage());  

    20.         }  

    21.     } //statisch  

    22.     public $Proxy0(InvocationHandler invocationhandler) {  

    23.         super(invocationhandler);  

    24.     }  

    25.     @Override  

    26.     public final boolean equals(Object obj) {  

    27.         Versuchen Sie es {  

    28.                       } 

      fangen (Wurfbar) {  
    29.             

      throw 
    30. new UndeclaredThrowableException(throwable);  
    31.         }  

    32.     }  

    33.     

      @Override  
    34.     

      public 
    35. final 
    36. int hashCode() {  

              

      versuchen {  
    37.             

      return ((Integer) 
    38. super.h.invoke(
    39. this, m0, 

      null)).intValue();          } 

      fangen (Wurfbar) {  
    40.             

      throw 
    41. new UndeclaredThrowableException(throwable);  
    42.         }  

    43.     }  

    44.     

      öffentliche 
    45. endgültige 
    46. void request() {  

              

      versuchen {  
    47.             

      super.h.invoke(
    48. this, m3, 
    49. null);  

                  

      zurück;  
    50.         } 

      catch (Error e) {  
    51.         } 

      catch (Throwable throwable) {
    52.             

      throw 
    53. new UndeclaredThrowableException(throwable);  
    54.         }  

    55.     }  

    56.     

      @Override  
    57.     

      public 
    58. final String toString() {  
    59.         

      try{  
    60.             

      return (String) 
    61. super.h.invoke(
    62. this, m2,

      null);          } 

      fangen (Wurfbar) {  
    63.             

      throw 
    64. new UndeclaredThrowableException(throwable);  
    65.         }  

    66.     }  

    67. }  



    68. Dann nimm den $, den du hast got Die Proxy0-Instanz wird in Subject umgewandelt und die Referenz wird dem Subject zugewiesen. Wenn die Methode subject.request() ausgeführt wird, wird die Methode request() in der Klasse $Proxy0 und dann die Methode invoke() von h in der übergeordneten Klasse Proxy aufgerufen. Das heißt, InvocationHandler.invoke().

      PS: 1. Eine Sache, die erklärt werden muss, ist, dass die getProxyClass-Methode in der Proxy-Klasse die Proxy-Klasse-Klasse zurückgibt. Der Grund, warum ich das erkläre, ist, dass ich zu Beginn einen Fehler auf niedriger Ebene gemacht habe und dachte, dass das, was zurückgegeben wurde, die „Klasse der Proxy-Klasse“ war – –! Es wird empfohlen, einen Blick auf den Quellcode von getProxyClass zu werfen. Er ist sehr lang =. =
      2. Aus dem Quellcode von $Proxy0 ist ersichtlich, dass die dynamische Proxy-Klasse nicht nur die Methoden in der explizit definierten Schnittstelle, sondern auch die geerbten equal() im Java-Root-Klassenobjekt weiterleitet , hashcode(), toString() und nur diese drei Methoden.

      F: Bis jetzt gibt es noch eine Frage: Der erste Parameter in der Aufrufmethode ist eine Instanz von Proxy (genauer gesagt wird letztendlich die Instanz von $Proxy0 verwendet), aber was? Was verwenden? Mit anderen Worten: Wie zeigt das Programm seine Wirkung?
      A: Auf meiner aktuellen Ebene hat dieser Proxy-Parameter keine Auswirkung. Im gesamten dynamischen Proxy-Mechanismus wird der Proxy-Parameter der Aufrufmethode in InvocationHandler nicht verwendet. Der übergebene Parameter ist tatsächlich eine Instanz der Proxy-Klasse. Ich denke, es könnte sein, dass Programmierer die Reflektion in der Aufrufmethode verwenden können, um einige Informationen über die Proxy-Klasse zu erhalten.

Das obige ist der detaillierte Inhalt vonTutorial zur Implementierung eines dynamischen Proxys in Java. Für weitere Informationen folgen Sie bitte anderen verwandten Artikeln auf der PHP chinesischen Website!

Stellungnahme:
Der Inhalt dieses Artikels wird freiwillig von Internetnutzern beigesteuert und das Urheberrecht liegt beim ursprünglichen Autor. Diese Website übernimmt keine entsprechende rechtliche Verantwortung. Wenn Sie Inhalte finden, bei denen der Verdacht eines Plagiats oder einer Rechtsverletzung besteht, wenden Sie sich bitte an admin@php.cn