Java - Mécanisme d'agent dynamique détaillé

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:

Copier le code
 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





Copier le code

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:

Copier le code
 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); 
    } 
}
Copier le code

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:

Copier le code
 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 ; 
    } 

}
Copier le code

Enfin, jetons un œil à notre classe Client:

Copier le code
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" ); 
    } 
}
Copier le code

Jetons d'abord un œil à la sortie de la console:

Copier le code
$ 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
Copier le code

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:

Copier le code
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 ; 
    }
Copier le code

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.


Publié 7 articles originaux · 69 éloges · 200 000+ vues

Je suppose que tu aimes

Origine blog.csdn.net/u014320421/article/details/79770743
conseillé
Classement