Cet article concerne un problème difficile à Java. En utilisant la bibliothèque Java Core pour implémenter des méthodes AOP simples et analyser et comparer le code d'instance. Ce qui suit est tout le contenu:
Le printemps est un cadre open source très populaire, et AOP (programmation en coupe) est l'un des concepts les plus importants du printemps. Afin de mieux comprendre et apprendre les idées d'AOP, utiliser la bibliothèque de base pour y parvenir à la fois est un bon moyen.
Tout d'abord, introduisons le concept d'AOP. AOP (programmation orientée vers l'aspect), c'est-à-dire la programmation orientée tangentielle. La programmation dite orientée tangentielle est l'idée de concevoir le code du point de vue d'une zone transversale. L'idée traditionnelle de la POO est d'utiliser l'héritage de l'encapsulation et le polymorphisme pour construire une relation hiérarchique verticale, mais il n'est pas adapté à définir des relations horizontales. L'idée AOP fournit un bon complément à cela.
Par exemple, le code de gestion des journaux est souvent dispersé horizontalement dans de nombreux niveaux d'objets, mais cela n'a rien à voir avec les fonctions centrales des objets correspondants. Il existe également de nombreux codes similaires, tels que la vérification de l'autorisation, la sortie de débogage, le traitement des transactions, etc., qui sont également les mêmes. Ce n'est pas propice à la réutilisation et à la gestion du code.
À l'heure actuelle, la technologie AOP a vu le jour. Il utilise la technologie de «coupe transversale» pour pénétrer profondément dans l'objet d'encapsulation, encapsuler les comportements communs qui affectent plusieurs classes dans un module réutilisable et le nommer «l'aspect», c'est-à-dire le tranchage. La soi-disant «section» est simplement encapsulée par la logique ou les responsabilités qui ne sont pas liées à l'entreprise mais qui sont appelées conjointement par le module commercial, ce qui est pratique pour réduire le code en double du système, réduire le couplage entre les modules, et propice à l'opérabilité et à la maintenabilité ultérieures.
Alors, comment AOP est-il implémenté?
La réponse est Dynamic Proxy (il y aura un autre chapitre sur le proxy pour plus de détails, donc je ne vais pas entrer dans les détails ici). Il existe deux façons d'implémenter le proxy dynamique, l'un est le proxy dynamique JDK, et l'autre est le proxy dynamique CGLIB.
Ensuite, utilisez deux méthodes pour créer un châtaignier simple.
Concevons d'abord un scénario, supposons que nous ayons une interface informatique icalCulator et une calculatrice de calculatrice de calculatrice qui implémente cette interface.
Interface publique icalCulator {// Opération d'ajout public int Add (int a, int b); // soustraction publique int soustrait (int a, int b); // Multiple public int multiply (int a, int b); // Dividation Public Int Define (int a, int b);} CLASSE PUBLIQUE CALCULATELIMPL implémente icalCulator {@Override public int Add (int a, int b) {return a + b; } @Override public int soustraire (int a, int b) {return a - b; } @Override public int multiply (int a, int b) {return a * b; } @Override public int define (int a, int b) {return a / b; }}Comment enregistrer le nombre total de fois que la méthode de la calculatrice est utilisée sans modifier le code interne de la classe de calculatrice d'origine?
Avec un proxy dynamique, c'est en fait très simple. Créez d'abord une classe et implémentez l'interface InvocationHandler, remplacez la méthode Invoke.
classe publique TestHandler implémente invocationhandler {private objet TargetObject; private int usetimes; // lie l'objet délégué et renvoie la classe proxy de l'objet public bind (objet TargetObject) {this.targetObject = TargetObject; return proxy.newproxyinstance (targetObject.getClass (). getClassOader (), targetObject.getClass (). getInterfaces (), this); } @Override Public Object Invoke (Proxy d'objet, méthode de la méthode, objet [] args) lève le throwable {// faire quelque chose avant (); Objet résultat = méthode.invoke (TargetObject, args); après(); Résultat de retour; } private void avant () {System.out.println ("Nous pouvons faire quelque chose avant de calculer."); } private void after () {usEtimes ++; System.out.println ("Utilisé:" + USETimes + "Times"); }}Bien qu'il semble y avoir un peu trop de code, la méthode principale est la méthode invoquée. L'objet résultat = méthode.invoke (TargetObject, args); Il équivaut à continuer à utiliser les paramètres d'origine pour exécuter la méthode d'origine. Les avantages avant et après sont des fonctions personnalisées, qui peuvent faire certaines choses que nous voulons faire avant et après l'exécution du code d'objet, telles que le nombre d'utilisation ici.
Dans la méthode Bind, l'objet proxy cible est passé et une instance de classe proxy est renvoyée. Ensuite, voyons comment utiliser:
classe publique TestProxy {public static void main (String [] args) {TestHandler proxy = new TestHandler (); IcalCulator Calculate = (icalCulator) proxy.bind (new CalculatorImpl ()); INT Result = Calculate.Add (1,2); System.out.println ("Résultat est:" + résultat); Résultat = calcul.Sougraire (3,2); System.out.println ("Résultat est:" + résultat); résultat = calculater.multiply (4,6); System.out.println ("Résultat est:" + résultat); résultat = calculater.devide (6,2); System.out.println ("Résultat est:" + résultat); }}Nous définissons d'abord un TestHandler, puis obtenons une instance proxy via la méthode Bind, puis nous pouvons utiliser cette instance directement. Les résultats de l'opération sont les suivants:
Nous pouvons faire quelque chose avant de calculer. Utilisé: 1 Résultat est: 3 Nous pouvons faire quelque chose avant de calculer. Utilisé: 2 Le résultat est: 1 Nous pouvons faire quelque chose avant de calculer. Utilisé: 3 Le résultat est: 24 Nous pouvons faire quelque chose avant de calculer. Utilisé: 4 Résultat est: 3
De cette façon, nous implémentons l'extension de code sans modifier le code interne de calculatrice.
Ensuite, utilisez CGLIB pour l'implémenter une fois.
Créez d'abord une classe pour implémenter l'interface MethodInterceptor et remplacer la méthode d'interception. D'autres codes sont similaires à l'utilisation du proxy JDK, mais le processus d'obtention d'objets proxy est différent.
La classe publique CGLIBProxy implémente MethodInterceptor {private int usETimes; cible d'objet privé; public objet getInstance (objet Target) {this.target = cible; Enhancer Enhancer = New Enhancer (); Enhancer.SetSuperclass (this.target.getClass ()); Enhancer.setCallback (this); return Enhancer.Create (); } @Override Public Object Intercept (objet O, méthode Méthode, objet [] Objets, méthodyProxy MethodProxy) lève lanceable {avant (); Objet résultat = methodProxy.invokesUper (o, objets); après(); Résultat de retour; } private void avant () {System.out.println ("Nous pouvons faire quelque chose avant de calculer."); } private void after () {usEtimes ++; System.out.println ("Utilisé:" + USETimes + "Times"); }}Testez-le:
classe publique TestCgliBproxy {public static void main (String [] args) {cglibproxy cglibproxy = new Cglibproxy (); IcalCulator Calculate = (icalCulator) cglibproxy.getInstance (new CalculatorImpl ()); INT Result = Calculate.Add (1,2); System.out.println ("Résultat est:" + résultat); Résultat = calcul.Sougraire (3,2); System.out.println ("Résultat est:" + résultat); résultat = calculer.Multiply (4,6); System.out.println ("Résultat est:" + résultat); résultat = calcul.devide (6,2); System.out.println ("Résultat est:" + résultat); }}Les résultats de l'opération sont les suivants:
Nous pouvons faire quelque chose avant de calculer. Utilisé: 1 Résultat est: 3 Nous pouvons faire quelque chose avant de calculer. Utilisé: 2 Le résultat est: 1 Nous pouvons faire quelque chose avant de calculer. Utilisé: 3 Le résultat est: 24 Nous pouvons faire quelque chose avant de calculer. Utilisé: 4 Résultat est: 3
Maintenant, nous obtenons le même résultat. (Deux packages sont requis, CGLIB-2.2.2.jar ASM-3.3.jar)
Les deux méthodes ont leurs propres forces. JDK Proxy doit configurer une interface avant d'implémenter le proxy. C'est son inconvénient et son avantage. L'inconvénient est que cela sera un peu plus gênant, et il ne peut pas proxyer ceux qui sont déjà encapsulés et n'implémentent pas l'interface. La méthode proxy CGLIB ne nécessite pas l'utilisation d'interfaces. Mais c'est aussi à cause de cela que le proxy JDK intercepte uniquement les méthodes qui écrasent les interfaces dans la classe, tandis que CGLIB intercepte tous les appels de méthode de la classe. Les deux ont leurs avantages et leurs inconvénients, donc des circonstances spécifiques doivent être analysées. Au printemps, deux modes proxy sont utilisés mélangés.