1. Définition du mode proxy
Fournissez un objet avec un objet proxy et l'objet proxy contrôle l'accès à l'objet d'origine, c'est-à-dire que le client ne manipule pas directement l'objet d'origine, mais manipule indirectement l'objet d'origine via l'objet proxy.
Un exemple de modèle de proxy célèbre est le comptage de référence: lorsque plusieurs copies d'un objet complexe sont nécessaires, le motif proxy peut être combiné avec le mode méta pour réduire la quantité de mémoire. Une approche typique consiste à créer un objet complexe et un proxy multiple, chaque proxy faisant référence à l'objet d'origine. Les opérations qui agissent sur l'agent seront transmises à l'objet d'origine. Une fois que tous les agents n'existent pas, des objets complexes sont supprimés.
Il est simple de comprendre le modèle proxy, mais en fait, il existe un modèle de proxy dans la vie:
Nous pouvons acheter des billets de train à la gare, mais nous pouvons également les acheter au bureau de vente de billets de train. Le bureau de vente de billets de train ici est l'agent des achats de billets à la gare. Autrement dit, nous émettons une demande d'achat de billets au point de vente. Le point de vente enverra la demande à la gare, et la gare enverra la réponse réussie à l'achat au point de vente, et le point de vente vous le dira à nouveau.
Cependant, les billets ne peuvent être achetés que dans le point de vente, mais pas des remboursements, tandis que les billets peuvent être achetés à la gare, de sorte que les opérations soutenues par l'agent peuvent être différentes de celles de l'objet commandé.
Permettez-moi de vous donner un autre exemple que vous rencontrerez lors de la rédaction d'un programme:
S'il existe un projet existant (vous n'avez pas de code source, vous ne pouvez l'appeler que) qui peut appeler INT Calcul (String Exp1) pour implémenter le calcul de l'expression du suffixe. Si vous souhaitez utiliser ce projet pour implémenter le calcul de l'expression de l'infixe, vous pouvez écrire une classe proxy et définir un calcul (String exp2). Ce paramètre EXP2 est une expression de l'infixe. Par conséquent, vous devez convertir l'expression de l'infixe en une expression de suffixe (prétraitement) avant d'appeler le calcul () du projet existant, puis d'appeler le calcul () du projet existant. Bien sûr, vous pouvez également recevoir la valeur de retour et effectuer d'autres opérations, telles que l'enregistrement du fichier (postprocess). Ce processus utilise le mode proxy.
Lorsque vous utilisez un ordinateur, vous rencontrerez également des applications en mode proxy:
Proxy à distance: nous ne pouvons pas accéder à Facebook à cause de GFW en Chine. Nous pouvons y accéder en parcourant le mur (configurant un proxy). Le processus d'accès est:
(1) L'utilisateur envoie la demande HTTP au proxy
(2) Le proxy envoie une demande HTTP au serveur Web
(3) Le serveur Web envoie la réponse HTTP au proxy
(4) Le proxy renvoie la réponse HTTP à l'utilisateur
2. Proxy statique
Le soi-disant proxy statique signifie qu'une classe de proxy est générée pendant l'étape de compilation pour terminer une série d'opérations sur l'objet proxy. Ce qui suit est le diagramme de classe de structure du motif de proxy:
1. Participants du modèle proxy
Il y a quatre rôles en mode proxy:
Interface de sujet: c'est-à-dire l'interface comportementale implémentée par la classe proxy.
Objet cible: c'est-à-dire que l'objet étant proxyé.
Objet proxy: le client proxy utilisé pour encapsuler la classe de sujets réelle est la structure du diagramme de classe du modèle proxy:
2. Idées de mise en œuvre du modèle d'agent
L'objet proxy et l'objet cible implémentent la même interface comportementale.
La classe proxy et la classe cible implémentent séparément la logique d'interface.
Instancier un objet cible dans le constructeur de la classe proxy.
Appeler l'interface comportementale de l'objet cible dans la classe proxy.
Si le client souhaite appeler l'interface comportementale de l'objet cible, il ne peut fonctionner que via la classe proxy.
3. Exemples de proxy statique
Ce qui suit est un exemple de chargement paresseux pour illustrer le proxy statique. Lorsque nous démarrons un système de service, il peut prendre beaucoup de temps pour charger une certaine classe. Afin d'obtenir de meilleures performances, lors du démarrage du système, nous n'initialisons souvent pas cette classe complexe, mais initialisez plutôt sa classe de proxy. Cela séparera les méthodes consommant des ressources utilisant le proxy pour la séparation, ce qui peut accélérer la vitesse de démarrage du système et réduire le temps d'attente de l'utilisateur.
Définir une interface de sujet
Sujet de l'interface publique {public void sayshello (); public void saygoodbye ();} Définissez une classe cible et implémentez l'interface du sujet
La classe publique RealSubject implémente le sujet {public void Sayshello () {System.out.println ("Hello World"); } public void saygoodbye () {System.out.println ("Goodbye World"); }} Définissez une classe proxy pour proxyer l'objet cible.
La classe publique StaticProxy implémente le sujet {private realSubject realSubject = null; public staticproxy () {} public void sayshello () {// Il est chargé à ce moment, le chargement paresseux if (realSubject == null) {realSubject = new realSubject (); } realSubject.sayHello (); } // La méthode Saygoodbye est la même ...} Définir un client
classe publique Client {public static void main (String [] args) {staticProxy sp = new staticProxy (); sp.sayhello (); sp.saygoodbye (); }}Ce qui précède est un exemple de test simple d'un proxy statique. Cela peut ne pas sembler pratique. Cependant, ce n'est pas le cas. À l'aide d'un proxy, nous pouvons également transformer les méthodes d'objet cible. Par exemple, une série de connexions est créée dans le pool de connexions de la base de données. Afin de s'assurer que les connexions sont rarement ouvertes, ces connexions ne sont presque jamais fermées. Cependant, nous avons toujours l'habitude de fermer la connexion ouverte. De cette façon, nous pouvons utiliser le mode proxy pour reproxie la méthode de fermeture dans l'interface de connexion et la modifier pour le recycler dans le pool de connexion de la base de données au lieu d'exécuter réellement la méthode de connexion # close. Il existe de nombreux autres exemples et vous devez en faire l'expérience vous-même.
3. Agent dynamique
Dynamic Proxy fait référence à la génération de classes de proxy dynamiquement au moment de l'exécution. C'est-à-dire que le bytecode de la classe proxy sera généré et chargé à l'exécution vers le chargeur de classe du proxy actuel. Par rapport aux classes de traitement statique, les classes dynamiques présentent de nombreux avantages.
Il n'est pas nécessaire d'écrire une classe d'encapsulation complètement identique pour le sujet réel. S'il existe de nombreuses méthodes dans l'interface de sujet, il est également difficile d'écrire une méthode proxy pour chaque interface. Si l'interface change, le thème réel et les classes proxy doivent être modifiés, ce qui n'est pas propice à la maintenance du système;
L'utilisation de certaines méthodes de génération de proxy dynamiques peut même formuler la logique d'exécution de la classe de proxy à l'exécution, améliorant ainsi considérablement la flexibilité du système.
Il existe de nombreuses façons de générer un proxy dynamique: le JDK est livré avec un proxy dynamique, CGLIB, Javassist, etc. Ces méthodes présentent leurs propres avantages et inconvénients. Cet article explore principalement l'utilisation de l'analyse dynamique du proxy et du code source dans JDK.
Voici un exemple pour expliquer l'utilisation du proxy dynamique dans JDK:
classe publique DynamicProxy implémente invocationHandler {private realSubject = null; Public Object Invoke (Object Proxy, Method Method, Object [] args) {if (realSubject == null) {realSubject = new realSubject (); } méthode.invoke (realSubject, args); return realSubject; }}Exemple de code client
public class Client {public static void main (Strings [] args) {sujet sujet = (sujet) proxy.newinstance (classloader.getSystemloader (), realSubject.class.getInterfaces (), new DynamicProxy ()); Sujet.sayhello (); Sujet.saygoodbye (); }}Comme on peut le voir à partir du code ci-dessus, nous devons utiliser le proxy dynamique dans JDK. Utilisez la méthode statique proxy.newinstance (classloader, interfaces [], invokehandler) pour créer une classe de proxy dynamique. La méthode NewInstance comporte trois paramètres, qui représentent le chargeur de classe, une liste d'interfaces que vous souhaitez implémenter la classe de proxy, et une instance qui implémente l'interface invokehandler. Le proxy dynamique a remis le processus d'exécution de chaque méthode à la méthode invoquée pour le traitement.
Le proxy dynamique JDK nécessite que le proxy doit être une interface, mais une classe simple ne peut pas. Les classes de proxy générées par JDK Dynamic Proxy hériteront de la classe de proxy, et la classe de proxy implémentera toute la liste d'interface que vous avez passé. Par conséquent, le type peut être jeté au type d'interface. Vous trouverez ci-dessous le diagramme de structure du proxy.
On peut voir que le proxy est toutes les méthodes statiques, donc si la classe de proxy n'implémente aucune interface, il s'agit du type de proxy et n'a aucune méthode d'instance.
Bien sûr, si vous vous joignez, vous devez proxy une classe qui n'implémente pas une certaine interface, et les méthodes de cette classe sont les mêmes que celles définies par d'autres interfaces, et elle peut être facilement implémentée à l'aide de la réflexion.
classe publique DynamicProxy implémente invokeHandler {// La classe que vous souhaitez proxy private cibleClass TargetClass = null; // Initialisez cette classe publique DynamicProxy (TargetClass TargetClass) {this.targetClass = TargetClass; } public Object Invoke (Object Proxy, Method Method, Object [] args) {// Utilisez la réflexion pour obtenir la classe que vous souhaitez proxy Méthode MyMethod = TargetClass.getClass (). GetDeclaredMethod (Method.GetName (), Method.GetParAmEterTypes ()); myMethod.setAccessible (true); retourner myMethod.invoke (TargetClass, args); }}4. JDK Dynamic Proxy Source Code Analysis (JDK7)
Après avoir regardé l'exemple ci-dessus, nous savons simplement utiliser le proxy dynamique. Cependant, il est toujours brumeux sur la façon dont la classe de proxy est créée, qui a appelé la méthode invoquée, etc. L'analyse suivante
1. Comment les objets proxy sont-ils créés?
Regardez d'abord le code source de la méthode Proxy.NewInstance:
Public Static Object NewProxyInstance (Classloader Loader, class <?> [] Interfaces, invocationHandler h) lève illégalArgumentException {} // obtenir des informations d'interface final classe <?> [] intfs = interfaces.clone (); Final SecurityManager sm = System.getSecurityManager (); if (sm! = null) {checkProxyAccess (Reflection.getCallerClass (), Loader, Intfs); } // Générer la classe de classe proxy <?> Cl = getProxyclass0 (chargeur, intfs); // ... ok regardons la première moitié premier}À partir du code source, on peut voir que la génération de classes de proxy dépend de la méthode getProxyclass0. Ensuite, jetons un coup d'œil au code source GetProxyclass0:
Classe statique privée <?> getProxyClass0 (classloader loder, class <?> ... interfaces) {// Le nombre de listes d'interface ne peut pas dépasser 0xffff if (interfaces.length> 65535) {lancez new illégalargumentException ("Interface limite dépassement"); } // Remarque Ici, l'explication suivante est donnée en détail pour retourner proxyclasscache.get (chargeur, interfaces); } L'explication de proxyclasscache.get est: si la classe proxy qui implémente la liste d'interface existe déjà, prenez-la directement du cache. S'il n'existe pas, on est généré par proxyclassfactory.
Avant de regarder le code source de proxyclasscache.get, comprenons brièvement proxyclassCache:
Private Static Final FaibleCache <classloader, classe <?> [], classe <? >> proxyClassCache = new LowerCache <> (new KeyFactory (), new proxyclassfactory ());
ProxyclassCache est un cache de type faible. Son constructeur a deux paramètres. L'un d'eux est le proxyclassfactory utilisé pour générer la classe de proxy. Ce qui suit est le code source de proxyclasscache.get:
Final class faiblecache <k, p, v> {... public v get (k key, p paramètre) {}}Ici k représente la clé, p représente les paramètres, v représente la valeur
public v get (k key, p paramètre) {// Java7 NulloBject Judgment Method, si le paramètre est vide, une exception avec le message spécifié sera lancée. Si ce n'est pas vide, retournez. Objets.RequiRenonnull (paramètre); // nettoie la structure des données de faiblehashmap qui contient des références faibles, qui est généralement utilisée pour mettre en cache Expungestalentries (); // Obtenez CacheKey à partir de l'objet de file d'attente CacheKey = CacheKey.ValueOf (Key, RefQueue); // Remplissez le fournisseur de chargement paresseux. Concurrent est une carte en filetage concurrentmap <objet, fournisseur <v>> valeursmap = map.get (cacheKey); if (valeursmap == null) {concurrentMap <objet, fournisseur <v>> oldValuesMap = map.putifabsent (cacheKey, valeursmap = new concurrenthashmap <> ()); if (oldValuesMap! = null) {valeursmap = oldValuesMap; }} // Créer une sous-clé et récupérer le fournisseur possible <v> stocké par ce // subky à partir de valeursmap objet subkey = objets.RequiRenonnull (subkeyfactory.apply (key, paramètre)); Fournisseur <v> fournisseur = valeursmap.get (subkey); Usine d'usine = null; while (true) {if (fournisseur! = null) {// Obtenez la valeur du fournisseur. Cette valeur peut être une réalisation d'usine ou de cache. // Les trois phrases suivantes sont le code de base, qui renvoie la classe qui implémente InvokeHandler et contient les informations requises. V valeur V = fournisseur.get (); if (value! = null) {return value; }} // sinon aucun fournisseur en cache // ou un fournisseur qui a renvoyé null (peut être une cachevalue effacée // ou une usine qui n'a pas réussi à installer la cachevalue) // Le processus suivant est le processus de remplissage du fournisseur if (factory == null) {// Créer une gamme} if (fournisseur == NULL) {// Remplissant l'offre} Else {pour remplir} La fonction de la boucle est d'obtenir en continu la classe qui implémente InvokeHandler. Cette classe peut être obtenue à partir du cache ou générée à partir de proxyfactoryClass.
L'usine est une classe interne qui implémente l'interface du fournisseur <v>. Cette classe remplace la méthode GET, et une méthode d'instance de type proxyfactoryClass est appelée dans la méthode GET. Cette méthode est le véritable moyen de créer une classe proxy. Voyons le code source de la méthode ProxyFactoryClass # Appliquer:
public class <?> appliquer (classloader chargeur, class <?> [] interfaces) {map <class <?>, booléan> interfaceset = new identityhashmap <> (interfaces.length); for (class <?> intf: interfaces) {/ * vérifiez que le chargeur de classe résout le nom de cette interface avec le même objet de classe. * / class <?> interfaceClass = null; Essayez {// Chargez des informations sur chaque interfaceClass = class.forname (intf.getName (), false, chargeur); } catch (classNotFoundException e) {} // Si la classe chargée avec votre propre charge de classe n'est pas égale à la classe dans laquelle vous avez transmis, lancez une exception si (interfaceClass! = intf) {Throw New illégalArgumentException (INTF + "n'est pas visible depuis le chargeur de classe"); } // Si le nouveau n'est pas un type d'interface if (! InterfaceClass.isInterface ()) {Throw New illégalArgumentException (interfaceClass.getName () + "n'est pas une interface"); } // Vérifiez si l'interface est répétée if (interfaceSet.put (interfaceClass, boolean.true)! = Null) {Throw New illégalArgumentException ("interface répétée:" + interfaceClass.getName ()); }} String proxyPKg = null; // package pour définir la classe proxy dans / * Enregistrez le package d'une interface proxy non publique afin que la classe proxy soit définie dans le même package. * Vérifiez que toutes les interfaces proxy non publiques sont dans le même package. * / // Ce paragraphe dépend de la question des interfaces qui ne sont pas publiques dans l'interface dans laquelle vous avez passé. Si c'est le cas, toutes ces interfaces doivent être définies dans un seul package. Sinon, lancez des exceptions pour (class <?> Intf: interfaces) {int flags = intf.getModifiers (); if (! Modifier.ispublic (flags)) {String name = intf.getName (); int n = name.LastIndexof ('.'); String pkg = ((n == -1)? "": Name.substring (0, n + 1)); if (proxyPkg == null) {proxyPkg = pkg; } else if (! pkg.equals (proxyPkg)) {lancer un nouveau IllégalArgumentException ("Interfaces non publiques de différents packages"); }}}} if (proxyPkg == null) {// Si pas d'interfaces proxy non publiques, utilisez com.sun.proxy package proxypkg = reflevutil.proxy_package + "."; } / * * Choisissez un nom pour la classe proxy à générer. * / Long num = nextUniqueNumber.getAndInCment (); // Générez le nom de classe de la classe de proxy aléatoire, $ proxy + num string proxyname = proxypkg + proxyclassnamePrefix + num; / * * Générez le fichier de classe de la classe proxy, renvoyez le flux d'octet * / byte [] proxyClassFile = proxyGenerator.GenerateProxyclass (proxyName, interfaces); essayez {return deficlass0 (chargeur, proxyname, proxyClassFile, 0, proxyClassFile.length); } catch (classformaterror e) {// finit New illégalArgumentException (e.toString ()); }}}Le proxyfactoryClass # Application est une méthode pour générer vraiment des classes de proxy, ce qui est en fait inexact. Après avoir lu le code source ici, nous constatons que ProxyGenerator # GenerateProxyClass est la méthode pour vraiment générer des classes de proxy. Générez le fichier de classe correspondant en fonction de la composition Bytecode de classe Java (voir mon autre article Java Bytecode Learning Notes). Le code source spécifique de ProxyGenerator # GenerateProxyclass est le suivant:
octet privé [] generateClassFile () {/ * * Étape 1: assembler des objets proxyméthodes pour toutes les méthodes pour * générer du code de répartition proxy pour. * / // La méthode AddProxyMethod consiste à ajouter toutes les méthodes à une liste et à correspondre à la classe correspondante // Voici trois méthodes correspondant à l'objet, toString et égal à addProxyMethod (hashcodemethod, object.class); addProxyMethod (equalsMethod, object.class); addProxyMethod (toStringMethod, object.class); // Comparez l'interface dans la liste d'interface avec les méthodes sous l'interface pour (int i = 0; i <interfaces.length; i ++) {méthode [] méthodes = interfaces [i] .getMethods (); pour (int j = 0; j <méthodes.length; j ++) {addProxyMethod (méthodes [j], interfaces [i]); }} / * * Pour chaque ensemble de méthodes de proxy avec la même signature, * Vérifiez que les types de retour des méthodes sont compatibles. * / for (list <proxymethod> SignMethods: proxymethods.values ()) {checkReturnTypes (sigMethods); } / * * Étape 2: Assemblez les structures FieldInfo et MethodInfo pour tous les champs et méthodes de la classe que nous générons. * / // Ajouter une méthode de constructeur à la méthode, qui n'est qu'un seul constructeur, qui est un constructeur avec l'interface invocationHandler.//c'est la méthode réelle pour ajouter une méthode au fichier de classe, c'est-à-dire la classe proxy. Cependant, il n'a pas encore été traité. Il est juste ajouté en premier et attendez la boucle. La description du nom du constructeur dans le fichier de classe est <Init> try {MethodS.Add (generateConstructor ()); for (list <proxymethod> signalThods: proxythods.values ()) {for (proxyméthod pm: signetods) {// ajouter un attribut de type de méthode à chaque méthode proxy. Le numéro 10 est l'identifiant du fichier de classe, ce qui signifie que ces attributs sont fields.add (new fieldInfo (pm.MethodFieldName " // Ajouter chaque méthode proxy aux méthodes de méthode de classe proxy.Add (pm.GenerateMethod ()); }} // Ajoutez un bloc d'initialisation statique et initialisez chaque attribut. Ici, le bloc de code statique est également appelé constructeur de classe. Il s'agit en fait d'une méthode avec le nom <clinit>, alors ajoutez-le aux méthodes de la liste des méthodes. } catch (ioException e) {lancer un nouveau interneurror ("exception d'E / S inattendue"); } // Le nombre de méthodes et d'attributs ne peut pas dépasser 65535, y compris le nombre précédent d'interfaces. // C'est parce que dans le fichier de classe, ces nombres sont représentés dans HexaDecimal 4 bits, donc la valeur maximale est de 2 à la puissance du 16e -1 if (méthodes.size ()> 65535) {lancez un nouveau IllégalArgumentException ("Méthode Limit dépasse"); } if (fields.size ()> 65535) {Throw New illégalArgumentException ("Field Limit dépasse"); } // L'étape suivante consiste à écrire un fichier de classe, y compris des numéros magiques, des noms de classe, des pools constants et d'autres séries de codes bytecodes. Je n'entrerai pas dans les détails. Si vous en avez besoin, vous pouvez vous référer aux connaissances pertinentes de la machine virtuelle JVM Bytecode. cp.getClass (dottoslash (className)); cp.getClass (superclassName); for (int i = 0; i <interfaces.length; i ++) {cp.getClass (dottoslash (interfaces [i] .getName ())); } cp.setReadOnly (); ByteArrayOutputStream Bout = new ByteArrayOutputStream (); DataOutputStream Dout = new DataOutputStream (Bout); essayez {// u4 magie; Dout.WriteInt (0xcafeBabe); // U2 Minor_version; Dout.WriteShort (classfile_minor_version); // U2 major_version; Dout.WriteShort (classfile_major_version); CP.Write (Dout); // (écrivez un pool constant) // U2 Access_Flags; Dout.WriteShort (ACC_PUBLIC | ACC_FINAL | ACC_SUPER); // u2 this_class; Dout.WriteShort (cp.getClass (dottoslash (className))); // u2 super_class; Dout.WriteShort (cp.getClass (superclassName)); // u2 interfaces_count; Dout.WriteShort (Interfaces.Length); // interfaces U2 [interfaces_count]; for (int i = 0; i <interfaces.length; i ++) {Dout.WriteShort (cp.getClass (dottoslash (interfaces [i] .getName ()))); } // u2 fields_count; Dout.WriteShort (Fields.Size ()); // field_info fields [fields_count]; pour (fieldInfo f: fields) {f.write (Dout); } // u2 Methods_Count; Dout.WriteShort (méthodes.size ()); // Method_Info Methods [Methods_Count]; pour (méthodeInfo m: méthodes) {M.Write (Dout); } // u2 attributs_count; Dout.WriteShort (0); // (pas d'attributs de fichiers de classe pour les classes de proxy)} catch (ioException e) {lancez new interneerror ("Exception d'E / S inattendue"); } return boout.toByTearray (); }Après des couches d'appels, une classe proxy est finalement générée.
2. Qui a appelé Invoke?
Nous simulons JDK pour générer une classe proxy en soi, avec le nom de classe TestProxygen:
classe publique TestGeneratorProxy {public static void main (String [] args) lève ioException {byte [] classfile = proxygenerator.generateProxyClass ("testProxygen", sujet.class.getInterfaces ()); File file = new File ("/ Users / Yadoao / Desktop / TestProxygen.class"); FileoutputStream fos = new FileOutputStream (fichier); Fos.Write (ClassFile); fos.flush (); fos.close (); }}Décompiler le fichier de classe avec JD-Gui, et le résultat est le suivant:
Importer com.su.dynamicproxy.isubject; import java.lang.reflect.invocationhandler; import java.lang.reflect.method; import java.lang.reflect.proxy; import java.lang.reflect.undeclaredthrowableexception; Public Final testproxyGen extension prolonge projette projette implect Isubject {private class testproxyGe extend prolonds proalty implect its IsubJe M3; Méthode statique privée M1; Méthode statique privée M0; Méthode statique privée M4; Méthode statique privée M2; Public TestProxygen (invocationHandler ParaminvocationHandler) lève {super (paraminvocationhandler); } public final void sayshello () lance {try {this.h.invoke (this, m3, null); retour; } catch (error | runtimeException localerror) {throw localerror; } catch (landable localthrowable) {lancez un nouveau UnclaredThrowableException (localthrowable); }} public final booléen equals (objet paramObject) lève {try {return ((boolean) this.h.invoke (this, m1, nouvel objet [] {paramobject})). booleanValue (); } catch (error | runtimeException localerror) {throw localerror; } catch (landable localthrowable) {lancez un nouveau UnclaredThrowableException (localthrowable); }} public final int hashcode () lance {try {return ((Integer) this.h.invoke (this, m0, null)). intValue (); } catch (error | runtimeException localerror) {throw localerror; } catch (landable localthrowable) {lancez un nouveau UnclaredThrowableException (localthrowable); }} public final void saygoodbye () lance {try {this.h.invoke (this, m4, null); retour; } catch (error | runtimeException localerror) {throw localerror; } catch (landable localthrowable) {lancez un nouveau UnclaredThrowableException (localthrowable); }} public final String toString () lance {try {return (string) this.h.invoke (this, m2, null); } catch (error | runtimeException localerror) {throw localerror; } catch (landable localthrowable) {lancez un nouveau UnclaredThrowableException (localthrowable); }} static {try {m3 = class.forname ("com.su.damicproxy.isubject"). getMethod ("sayhello", new class [0]); m1 = class.forname ("java.lang.object"). getMethod ("equals", new class [] {class.forname ("java.lang.object")}); m0 = class.forname ("java.lang.object"). getMethod ("hashcode", new class [0]); m4 = class.forname ("com.su.damicproxy.isubject"). getMethod ("saygoodbye", new class [0]); m2 = class.forname ("java.lang.object"). getMethod ("toString", new class [0]); retour; } catch (NosuchMethodexception localNosuchMethodexception) {lance un nouveau NoSuchMethoDerror (localNosuchMethodexception.getMessage ()); } catch (classNotFoundException localClassNotFoundException) {Throw New NoclassdeffoundError (localClassNotFoundException.GetMessage ()); }}} Tout d'abord, j'ai remarqué que le constructeur de la classe de procuration générée est passé dans une classe qui implémente l'interface invokehandler en tant que paramètre, et appelé le constructeur du proxy de la classe parent, qui a initialisé la variable de membre protégée invokehander H dans le proxy.
J'ai à nouveau remarqué plusieurs blocs d'initialisation statiques. Le bloc d'initialisation statique ici consiste à initialiser la liste d'interface proxy et le code hashcode, le tostring et l'égalité des méthodes.
Enfin, il y a le processus d'appel de ces méthodes, qui sont tous des rappels à la méthode invoquée.
Cela se termine par l'analyse de ce modèle de proxy.