Maison >Java >javaDidacticiel >Tutoriel sur l'implémentation d'un proxy dynamique en Java

Tutoriel sur l'implémentation d'un proxy dynamique en Java

零下一度
零下一度original
2017-06-30 09:52:451330parcourir

Le contenu suivant est partiellement basé sur du contenu sur Internet. Je tiens à exprimer ma gratitude à l'auteur original !

La clé de l'implémentation du proxy dynamique en Java réside dans ces deux éléments : Proxy et InvocationHandler Commençons par la méthode Invocation dans l'interface InvocationHandler et expliquons brièvement comment Java implémente le proxy dynamique.
Premièrement, la forme complète de la méthode d'invocation est la suivante :

Java code Tutoriel sur limplémentation dun proxy dynamique en Java
  1. public Object Invocation (Object Proxy, Method Method, Object[] args) lance Throwable

  2. 🎜>

  3.  
  4. retour

    null ; 

  5.  } 
  6. Première hypothèse, la méthode est la méthode appelée, c'est-à-dire la méthode qui doit être exécutée ; les arguments sont les paramètres de la méthode proxy, quel est ce paramètre ? L'implémentation ci-dessus de la méthode Invoke() est une forme relativement standard. Nous voyons que le paramètre proxy n'est pas utilisé ici. Consultez la description de Proxy dans la documentation du JDK, comme suit :


Code Java

Une invocation de méthode sur une instance proxy via l'une de ses interfaces proxy sera envoyée à la méthode d'invocation du gestionnaire d'invocation de l'instance, en passant le instance proxy, un objet java.lang.reflect.Method identifiant la méthode qui a été invoquée et un tableau de type Object contenant les arguments
Tutoriel sur limplémentation dun proxy dynamique en Java
.
  1. À partir de là, nous pouvons savoir que la supposition ci-dessus est correcte, et nous savons également que le paramètre proxy reçoit une instance de la classe proxy.
Pour faciliter l'explication, voici un exemple simple pour implémenter un proxy dynamique.






Code Java

//Rôle abstrait (le proxy dynamique ne peut proxy que les interfaces proxy)
Tutoriel sur limplémentation dun proxy dynamique en Java
public
    interface Sujet {
  1. public void request();


Code Java

  1. //Rôle réel : Implémentation de la méthode request() du sujet

  2. public class RealSubject implémente Sujet{

  3. public demande d'annulation(){

  4. System.out.println("À partir d'un sujet réel.");

  5. }

  6. }

Java code

//Implements InvocationHandler
Tutoriel sur limplémentation dun proxy dynamique en Java public
class DynamicSubject
implémente InvocationHandler
  1. {
  2. private Object obj;//Il s'agit d'un proxy dynamique L'avantage est que l'objet encapsulé est de type Objet, acceptant tout type d'objet

  3. public DynamicSubject () 

  4.                                                   🎜>
  5. >DynamicSubject public (Obj objet)

  6. {

  7. this.obj = obj ; 

  8.                                                                 Appel explicite

  9. Invocation d'objet public (proxy d'objet, méthode de méthode, arguments Object[])
  10. lance Throwable

  11. {

  12. System.out.println(

    "avant d'appeler " + méthode); 🎜> method.invoke(obj, args); //-----> Veuillez lire l'article suivant pour plus de détails sur cette étape. Java appelle une certaine fonction via un mécanisme de réflexion. Vous comprendrez les méthodes de chaque classe après les avoir lues. .

  13. System.out.println(
  14. "après avoir appelé " + méthode);

  15.                                                                                          🎜>

  16. Code Java

    1. //Client : généré une instance proxy et appelé la méthode request()

    2. classe publique Client {

    3. public statique void main(String[] args ) lancers Throwable{

    4. 🎜>

    5. Subject rs=

      new RealSubject();
    6. //Spécifiez la classe proxy ici
    7. InvocationHandler ds=

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

                                                                    🎜>> ); >                                                                                                             🎜>
    9. System.out.println( subject

      instanceof Proxy);
    10.  

      //On voit ici que la classe Class du sujet est $Proxy0. Cette classe $Proxy0 hérite de Proxy et implémente l'interface Sujet
    11. System.out (
    12. "la classe Class du sujet est : "+subject.getClass. ().toString());

    13. System.out.print(

      "Les attributs du sujet sont : ");
    14. Field[ ] field=subject.getClass().getDeclaredFields();

    15. > System.out.print(f.getName()+
    16. ", "

    17. }

    18. System.out.print(

      "n"+
    19. "Les méthodes dans le sujet sont : "
    20. Method[] method=subject.getClass().getDeclaredMethods();
    21.                                                                              ) >"n"+
    22. " ; La classe parent du sujet est : "+subject.getClass().getSuperclass());
    23. System.out.print(

      "n"+
    24. "L'interface implémentée par sujet est : " );
    25. Classe>[] interfaces=subject.getClass().getInterfaces() ;

    26. pour (Classe> i:interfaces){
    27.   System.out.print(i.getName()+
    28. ", "

      );
    29. }

    30. System.out.println("nn"+ "Le résultat de l'opération est : " ;

    31. subject.request();

    32. }

    33. >


Code XML Tutoriel sur limplémentation dun proxy dynamique en Java
  1. Les résultats d'exécution sont les suivants : le nom du package est omis ici, *** est remplacé par

  2. true

  3. Classe du sujet C'est : class $Proxy0

  4. Les attributs du sujet sont : m1, m3, m0, m2,

  5. Les méthodes dans le sujet sont : request , hashCode, equals, toString,

  6. la classe parent du sujet est : class java.lang.reflect.Proxy

  7. L'interface implémentée par subject est :cn.edu.ustc.dynamicproxy.Subject,  

  8. Le résultat courant est :  

  9. avant d'appeler public abstract void ***.Subject.request()

  10. À partir du sujet réel

  11. après avoir appelé public abstract void ** *.Subject.request()


PS : Les informations contenues dans ce résultat sont très importantes, du moins pour moi. Parce que la cause première de ma confusion à propos du proxy dynamique est que j'ai mal compris le sujet.request() ci-dessus. Au moins, j'ai été confus par la surface, je n'ai pas trouvé le lien entre le sujet et le proxy. de request( ) est connecté à Ensure(), et comment Invoke sait-il que cette requête existe. En fait, le vrai et la classe $Proxy0 ci-dessus peuvent résoudre de nombreuses questions. Avec le code source de $Proxy0 mentionné ci-dessous, il peut complètement résoudre les doutes concernant le proxy dynamique.

Comme vous pouvez le voir à partir du code et des résultats ci-dessus, nous n'avons pas explicitement appelé la méthode Invoke(), mais cette méthode a bel et bien été exécutée. Analysons l'ensemble du processus :

À partir du code dans le client, nous pouvons utiliser la méthode newProxyInstance comme une percée. Jetons d'abord un coup d'œil au code source de la méthode newProxyInstance dans la classe Proxy :

Code Java
Tutoriel sur limplémentation dun proxy dynamique en Java
  1. public static Object newProxyInstance (ClassLoader loader,  

  2.         Class>[] interfaces,

  3.         InvocationHandler h)  

  4. lance IllegalArgumentException  

  5. {  

  6.     if (h == null) {  

  7.         lancer nouveau NullPointerException();  

  8.     }  

  9.     /* 

  10.      * Recherchez ou générez la classe proxy désignée. 

  11.      */  

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

  13.     /* 

  14.      * Invoquer son constructeur avec le gestionnaire d'appel désigné. 

  15.      */  

  16.     essayer {  

  17.            /* 

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

  19.             * classe statique finale privée[] constructorParams = { InvocationHandler.class } ; 

  20.             * cons即是形参为InvocationHandler类型的构造方法 

  21.            */

  22.         Constructeur cons = cl.getConstructor(constructorParams);  

  23.         return (Object) cons.newInstance(new Object[] { h });  

  24.     } attraper (NoSuchMethodException e) {  

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

  26.     } catch (IllegalAccessException e) {  

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

  28.     } catch (InstantiationException e) {  

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

  30.     } catch (InvocationTargetException e) {  

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

  32.     }  

  33. }  



Proxy.newProxyInstance (chargeur ClassLoader, classe> ;[] interfaces, InvocationHandler h) a fait les choses suivantes.
                                             (1) Appelez la méthode getProxyClass(loader, interfaces) en fonction des paramètres du chargeur et des interfaces pour créer la classe proxy $Proxy0. La classe $Proxy0 implémente l'interface. des interfaces, et a hérité de la classe Proxy.
(2) Instanciez $Proxy0 et transmettez DynamicSubject dans le constructeur. Ensuite, $Proxy0 appelle le constructeur de la classe parent Proxy et attribue une valeur à h, comme suit :
proxy de classe{

InvocationHandler h=
null ;
Tutoriel sur limplémentation dun proxy dynamique en Java
proxy protégé (InvocationHandler h) { = h;                            
  1. Jetons un coup d'œil au code source de $Proxy0 qui hérite du Proxy :

  2. Code Java

  1. public final class $Proxy0 étend Proxy implémente Subject {  

  2.     privé Méthode statique m1 ;  

  3.     privée Méthode statique m0 ;  

  4.     privé Méthode statique m3 ;  

  5.     privé Méthode statique m2 ;  

  6.     statique {  

  7. essayez {  

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

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

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

  11.                    nouvelle Classe[0]);  

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

  13.                    nouvelle Classe[0]);  

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

  15.                    nouvelle Classe[0]);  

  16.         } catch (NoSuchMethodException nosuchmethodexception) {  

  17.             lancer new NoSuchMethodError(nosuchmethodexception.getMessage());  

  18.         } catch (ClassNotFoundException classnotfoundexception) {  

  19.             lancer  new NoClassDefFoundError(classnotfoundexception.getMessage());  

  20.         }  

  21.     } //statique  

  22.     public $Proxy0(InvocationHandler invocationhandler) {  

  23.         super(invocationhandler);  

  24.     }  

  25.     @Override  

  26.     public final boolean equals(Object obj) {  

  27.         essayez {  

  28.             return ((Boolean) super.h.invoke(this, m1, new Object[] { obj })) .booleanValue();  

  29.          } attrape (Jetable jetable) {  

  30.              lancer nouvelle UndeclaredThrowableException(throwable);  

  31.          }  

  32.     }  

  33.     @Override  

  34.     public final int hashCode() {  

  35.         essayer {  

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

  37.          } attrape (Jetable jetable) {  

  38.              lancer nouvelle UndeclaredThrowableException(throwable);  

  39.          }  

  40.     }  

  41.     public final void request() {  

  42.         essayer {  

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

  44.             retour ;  

  45.         } attraper (Erreur e) {  

  46.          } attraper (jetable jetable) {

  47.             lancer nouvelle UndeclaredThrowableException(throwable);  

  48.          }  

  49.     }  

  50.     @Override  

  51.     public final String toString() {  

  52.         essayer {  

  53.            return (String) super.h.invoke(this, m2, nul);  

  54.          } attrape (Jetable jetable) {  

  55.              lancer nouvelle UndeclaredThrowableException(throwable);  

  56.          }  

  57.     }  

  58. }  



Alors prends les $ que tu got L'instance Proxy0 est convertie en Sujet et la référence est affectée au sujet. Lorsque la méthode subject.request() est exécutée, la méthode request() de la classe $Proxy0 est appelée, puis la méthode Invocation() de h dans la classe parent Proxy est appelée.

PS : 1. Une chose qui doit être expliquée est que la méthode getProxyClass dans la classe Proxy renvoie la classe Proxy Class. La raison pour laquelle j'explique cela est parce que j'ai commis une erreur de bas niveau au début, pensant que ce qui était renvoyé était la "Classe de la classe mandatée" - - ! Il est recommandé de jeter un œil au code source de getProxyClass, il est très long =. =
2. Il ressort du code source de $Proxy0 que la classe proxy dynamique non seulement proxy les méthodes dans l'interface explicitement définie, mais également proxy les égal(s) hérités dans la classe racine Java Object , hashcode(), toString() et uniquement ces trois méthodes.

Q : Jusqu'à présent, il y a encore une question. Le premier paramètre de la méthode d'invocation est une instance de Proxy (pour être précis, l'instance de $Proxy0 est finalement utilisée), mais quoi ? Quoi utiliser ? En d’autres termes, comment le programme montre-t-il son effet ?
A : De mon niveau actuel, ce paramètre proxy n'a aucun effet. Dans l'ensemble du mécanisme de proxy dynamique, le paramètre proxy de la méthode d'invocation dans InvocationHandler n'est pas utilisé. Le paramètre transmis est en fait une instance de la classe proxy. Je pense que cela pourrait permettre aux programmeurs d'utiliser la réflexion dans la méthode d'invocation pour obtenir des informations sur la classe proxy.

Ce qui précède est le contenu détaillé de. pour plus d'informations, suivez d'autres articles connexes sur le site Web de PHP en chinois!

Déclaration:
Le contenu de cet article est volontairement contribué par les internautes et les droits d'auteur appartiennent à l'auteur original. Ce site n'assume aucune responsabilité légale correspondante. Si vous trouvez un contenu suspecté de plagiat ou de contrefaçon, veuillez contacter admin@php.cn