Lors de l'apprentissage de Spring, nous savons que Spring a deux idées principales, l'une est IoC et l'autre est AOP. Pour IoC, l'injection de dépendance n'a pas besoin d'en dire beaucoup, et pour le noyau AOP de Spring, nous avons non seulement besoin de savoir comment passer AOP pour répondre à nos fonctions, nous devons en savoir plus sur le principe sous-jacent, et le principe d'AOP est le mécanisme de proxy dynamique de java, donc cet essai est une revue du mécanisme dynamique de java.
Dans le mécanisme de proxy dynamique de java, il existe deux classes ou interfaces importantes, l'une est InvocationHandler (Interface), l'autre est Proxy (Classe), cette classe et cette interface sont nécessaires pour obtenir notre proxy dynamique. Voyons d'abord comment la documentation d'aide de l'API Java décrit ces deux classes:
InvocationHandler:
InvocationHandler est l'interface implémentée par le gestionnaire d'invocation d'une instance de proxy.
Chaque instance de proxy a un gestionnaire d'invocation associé. Lorsqu'une méthode est invoquée sur une instance proxy, l'invocation de la méthode est codée et envoyée à la méthode invoke de son gestionnaire d'invocation.
Chaque classe de proxy dynamique doit implémenter l'interface InvocationHandler et chaque instance de la classe proxy est associée à un gestionnaire. Lorsque nous appelons une méthode via l'objet proxy, l'appel de méthode est transmis à l'interface de InvocationHandler Pour appeler la méthode invoke. Jetons un coup d'œil à la seule méthode d' invocation de l'interface d'InvocationHandler :
Invocation de l' objet (proxy de l' objet, méthode Méthode, Object [] args) lance Throwable
Nous voyons que cette méthode accepte un total de trois paramètres, alors que représentent ces trois paramètres?
Objet Invoke (Object Proxy, méthode Méthode ,, Object [] args) throws Throwable Proxy : reportez - vous à l'objet réel , nous sommes des agents de méthode, : fait référence à un objet méthode que nous voulons appeler une méthode d'un objet réel de args : reportez - vous à la Le paramètre est-il accepté lors de l'appel d'une méthode sur un objet réel
Si vous ne le comprenez pas, nous expliquerons ces paramètres plus en détail à travers un exemple.
Ensuite, jetons un œil à la classe Proxy:
Le proxy fournit des méthodes statiques pour créer des classes et des instances de proxy dynamiques, et il s'agit également de la superclasse de toutes les classes de proxy dynamiques créées par ces méthodes.
Le rôle de la classe Proxy est de créer dynamiquement une classe d'objets proxy, qui fournit de nombreuses méthodes, mais nous utilisons le plus la méthode newProxyInstance :
public static Object newProxyInstance (chargeur ClassLoader, interfaces Class <?> [], InvocationHandler h) lève IllegalArgumentException
Renvoie une instance d'une classe proxy pour les interfaces spécifiées qui distribue les appels de méthode au gestionnaire d'invocation spécifié.
Le rôle de cette méthode est d'obtenir un objet proxy dynamique, qui reçoit trois paramètres, examinons la signification de ces trois paramètres:
objet statique public newProxyInstance (chargeur ClassLoader, interfaces Class <?> [], InvocationHandler h) lève le chargeur IllegalArgumentException : un objet ClassLoader, qui définit quel objet ClassLoader charger les interfaces d' objets proxy générées : un tableau d'objets Interface, représentant Ce que je veux, c'est de fournir un ensemble d'interfaces pour les objets dont j'ai besoin pour le proxy, si je lui fournis un ensemble d'interfaces, alors l'objet proxy prétend implémenter l'interface (polymorphisme), afin que je puisse appeler cet ensemble d'interfaces La méthode est h : un objet InvocationHandler, qui indique à quel objet InvocationHandler sera associé lorsque mon objet proxy dynamique appelle la méthode
Eh bien, après avoir introduit ces deux interfaces (classes), regardons un exemple pour voir à quoi ressemble notre modèle de proxy dynamique:
Nous définissons d'abord une interface de type Subject et lui déclarons deux méthodes:
interface publique Sujet { public void rent (); bonjour public void (String str); }
Ensuite, définissez une classe pour implémenter cette interface, cette classe est notre véritable objet, la classe RealSubject:
classe publique RealSubject implémente Subject { @Override public void rent () { System.out.println ( "Je veux louer ma maison" ); } @Override public void hello (String str) { System.out.println ( "hello:" + str); } }
Ensuite, nous devons définir une classe de proxy dynamique. Comme mentionné précédemment, chaque classe de proxy dynamique doit implémenter l'interface InvocationHandler, donc notre classe de proxy dynamique ne fait pas exception:
classe publique DynamicProxy implémente InvocationHandler { // Il s'agit de l'objet réel que nous voulons proxy objet privé Object; // Méthode de construction, affectez la valeur initiale à l'objet réel que nous voulons proxy proxy DynamicProxy public (objet) { this .subject = subject; } @ remplacer publique objet Invoke (Object objet, Méthode, Méthode ,, Object [] args) lance Throwable { // devant l'agence objet réel , nous pouvons ajouter quelques - unes de leurs propres opérations System.out.println ( "l'avant Location Maison" ); System.out. println ( "Méthode:" + méthode); // Lorsque l'objet proxy appelle la méthode de l'objet réel, il passe automatiquement à la méthode invoke de l'objet gestionnaire associé à l'objet proxy pour appeler method.invoke (subject, args); // Nous pouvons également en ajouter après l'objet réel proxy Propre opération System.out.println ("après location maison" ); return null ; } }
Enfin, jetons un œil à notre classe Client:
public class Client { public static void main (String [] args) { // L'objet réel que nous voulons proxy Sujet realSubject = new RealSubject (); // Quel objet réel nous voulons proxy, passer l'objet et enfin passer Le véritable objet pour appeler sa méthode InvocationHandler handler = new DynamicProxy (realSubject); / * * La méthode newProxyInstance du proxy pour créer notre objet proxy, regardons ses trois paramètres * Le premier paramètre handler.getClass () .getClassLoader (), nous utilisons l'objet ClassLoader de la classe gestionnaire pour charger notre objet proxy * Le deuxième paramètre realSubject.getClass (). getInterfaces (), l'interface que nous fournissons ici pour l'objet proxy est l'interface implémentée par l'objet réel , Indiquant que je veux proxyer l'objet réel, afin de pouvoir appeler les méthodes de cet ensemble d'interfaces * Le troisième gestionnaire de paramètres, nous associons cet objet proxy à l'objet InvocationHandler ci-dessus * / Subject subject =(Objet) Proxy.newProxyInstance (handler.getClass (). GetClassLoader (), realSubject .getClass (). GetInterfaces (), gestionnaire); System.out.println (subject.getClass (). GetName ()); subject.rent (); subject.hello ( "monde" ); } }
Jetons d'abord un œil à la sortie de la console:
$ Proxy0 avant location maison Méthode: résumé public void com.xiaoluo.dynamicproxy.Subject.rent () Je veux louer ma maison après location maison avant location maison Méthode: public abstract void com.xiaoluo.dynamicproxy.Subject.hello (java. lang.String) bonjour: monde après location maison
Voyons d'abord la chose $ Proxy0. Nous voyons que cette chose est imprimée par System.out.println (subject.getClass (). GetName ()); c'est pourquoi nous avons renvoyé cet objet proxy Le nom de la classe est comme ça?
Subject subject = (Subject) Proxy.newProxyInstance (handler.getClass (). GetClassLoader (), realSubject
.getClass (). GetInterfaces (), handler);
Peut-être que je pensais que l'objet proxy retourné serait un objet de type Subject, ou un objet d'InvocationHandler, mais le résultat n'est pas. D'abord, expliquons pourquoi nous pouvons le convertir en un objet de type Subject ici? La raison en est que sur le deuxième paramètre de la méthode newProxyInstance, nous fournissons un ensemble d'interfaces pour l'objet proxy, puis mon objet proxy implémentera cet ensemble d'interfaces, à ce moment, nous pouvons bien sûr convertir l'objet proxy en conversion de type obligatoire Pour n'importe lequel de ce groupe d'interfaces, car l'interface ici est du type Subject, elle peut être convertie en type Subject .
Dans le même temps, nous devons nous rappeler que l'objet proxy créé par Proxy.newProxyInstance est un objet généré dynamiquement lorsque le jvm est en cours d'exécution. Ce n'est pas notre type InvocationHandler ni le type de groupe d'interface que nous avons défini, mais il est en cours d'exécution. Un objet généré dynamiquement, et la méthode de dénomination est sous cette forme, en commençant par $, le proxy est dedans, et le dernier nombre indique l'étiquette de l'objet .
Ensuite, nous jetons un oeil à ces deux phrases
subject.rent ();
subject.hello ("monde");
Voici la méthode du type d'interface implémentée via l'objet proxy. À ce stade, le programme passera à la méthode invoke dans le gestionnaire associé à l'objet proxy à exécuter, et notre objet gestionnaire accepte un RealSubject. Le paramètre type indique que c'est cet objet réel que je veux proxy, donc à ce moment, la méthode invoke dans le gestionnaire sera appelée pour s'exécuter:
publique Objet Invoke (Object Object, Méthode, Méthode ,, Object [] args) lance Throwable { // devant l'agence objet réel , nous pouvons ajouter un peu de leurs propres opérations System.out.println ( "l'avant Location Maison" ); System.out.println ( "Method:" + method); // Lorsque l'objet proxy appelle la méthode de l'objet réel, il passe automatiquement à la méthode invoke de l'objet gestionnaire associé à l'objet proxy pour appeler method.invoke (subject, args); / / Après avoir mandaté des objets réels, nous pouvons également ajouter certaines de nos propres opérations System.out.println ("after rent house" ); return null ; }
Nous voyons que lorsque la méthode de l'objet réel est appelée via l'objet proxy, nous pouvons ajouter certaines de nos propres opérations avant et après la méthode, et nous voyons que notre objet méthode est comme ceci:
résumé public vide com.xiaoluo.dynamicproxy.Subject.rent () résumé public vide com.xiaoluo.dynamicproxy.Subject.hello (java.lang.String)
Il se trouve qu'il y a deux méthodes dans notre interface Subject, ce qui prouve que lorsque j'appelle une méthode via un objet proxy, elle est en fait déléguée pour être invoquée par la méthode invoke de l'objet gestionnaire auquel elle est associée, pas par moi-même. Appel réel, mais appelez via l'agent.
Ceci est notre mécanisme de proxy dynamique java
Cet essai explique en détail le mécanisme de proxy dynamique en Java. Ce point de connaissance est très important, y compris notre AOP Spring qui est implémenté via le mécanisme de proxy dynamique, nous devons donc bien comprendre le mécanisme de proxy dynamique.