introduire
Comme nous le savons tous, AOP (programmation axée sur la section) est l'une des caractéristiques des cadres de printemps. AOP offre une évolutivité extrêmement élevée en fixant des préoccupations de coupe croisée. Alors, comment fonctionne AOP au printemps? Lorsque vous ne pouvez utiliser que Core Java mais que vous avez besoin d'une technologie AOP, la réponse à cette question devient extrêmement critique. Non seulement cela, dans les entretiens pour des postes techniques avancés, de telles questions apparaissent souvent comme des questions de test. Regardez, mon ami a récemment assisté à une interview et on a posé une question si difficile - comment implémenter AOP sans utiliser le printemps et les bibliothèques connexes, et uniquement Java de base. Par conséquent, je vais fournir un aperçu de cet article pour vous aider à comprendre comment implémenter un AOP en utilisant Core Java (bien sûr, cet AOP a certaines limites fonctionnelles). Notez que cet article n'est pas une étude comparative de Spring AOP et Java AOP, mais un tutoriel sur la mise en œuvre de l'AOP à l'aide de modèles de conception inhérents dans Core Java.
Je crois que les lecteurs savent déjà ce qu'est AOP et comment l'utiliser dans le framework Spring, donc cet article se concentre uniquement sur la façon d'implémenter AOP sans utiliser Spring. Tout d'abord, nous devons savoir que Spring utilise deux technologies: JDK Proxy et CGLIB pour implémenter AOP. JDK Dynamic Proxy fournit un moyen flexible de connecter une méthode et d'effectuer des opérations spécifiées, mais il doit y avoir une restriction lors de l'exécution des opérations: une interface connexe et la classe d'implémentation de l'interface doit être fournie en premier. Pratiquez pour créer de vraies connaissances, comprenons cette phrase à travers une affaire! Il existe maintenant un programme de calculatrice pour effectuer des opérations mathématiques. Considérons la fonction de division. La question à l'heure actuelle est: si le cadre principal a déjà un code pour implémenter la division, pouvons-nous le détourner et effectuer une vérification supplémentaire lorsque le code est exécuté? La réponse est oui, et je le prouverai avec l'extrait de code fourni ci-dessous. Regardons d'abord le code de l'interface de base:
Calculatrice d'interface publique {public int calcul (int a, int b);}Le code de cette classe d'implémentation d'interface est le suivant:
Class de classe publique CalculatorIMPl implémente la calculatrice {@Override public int calcul (int a, int b) {return a / b; }}En supposant que nous ne pouvons pas réparer le code ci-dessus ou apporter des modifications à la bibliothèque principale, comment pouvons-nous parfaitement implémenter la fonction de vérification? Pourquoi ne pas essayer la fonction proxy dynamique JDK.
classe publique SomeHandler implémente InvocationHandler {// Code omis pour simplicité… .. @Override Object Invoke (proxy objet, méthode de la méthode, objet [] params) lève le throwable {// votre validation commerciale complexe et le résultat de l'objet logique = méthode.invoke (cibleObject, params); Résultat de retour; }}Voyons comment la fonction de vérification implémentée par JDK Dynamic Proxy fonctionne via la classe de test.
public static void main (String [] args) {calculatImpl calmplt = new CalculatorImpl (); Calculatrice proxied = (calculatrice) proxyfactory.getProxy (calculatrice.class, calcimpl, nouveau quelque part (calcimpl)); Int result = proxied.calculate (20, 10); System.out.println ("Résultat final :::" + Résultat); }D'après les résultats, nous pouvons voir qu'en implémentant simplement la puissante interface InvocationHandler, nous pouvons obtenir une implémentation d'accrochage. Selon la documentation JDK, l'interface InvocationHandler utilise une instance proxy pour gérer un appel de méthode.
Maintenant, nous savons que la méthode invoke () d'invocationHandler peut nous aider à résoudre le problème. Alors résolvons un nouveau problème - comment pouvons-nous effectuer des opérations avant et après l'exécution de la méthode? Pour le dire plus spécifiquement, pouvons-nous accrocher une méthode en ajoutant plusieurs AOP (avant, après, autour) (Note du traducteur: Le texte d'origine est Ajouter plusieurs AOP, mais je pense que Handler agit comme un aspect)? La réponse est aussi oui. Suivez les étapes ci-dessous pour créer un modèle de code rationalisé pour répondre à cette exigence:
Deux façons de mettre en œuvre AOP:
1. Implémentation de proxy dynamique fournie par JDK
interface
Interface publique UserBean {void GetUser (); void addUser (); void UpdateUser (); void DeleteUser (); } Classe d'implémentation originale
classe publique UserBeanIMPl implémente UserBean {private String user = null; public userbeanImpl () {} public userbeanImpl (String User) {this.user = user; } public String getUserName () {return user; } public void GetUser () {System.out.println ("This is GetUser () Method!"); } public void SetUser (String User) {this.user = user; System.out.println ("Ceci est SetUser () Méthode!"); } public void addUser () {System.out.println ("This is AddUser () Method!"); } public void UpdateUser () {System.out.println ("Ceci est UpdateUser () Méthode!"); } public void DeleteUser () {System.out.println ("Ceci est DeleteUser () Méthode!"); }} Classe d'agent
import java.lang.reflect.invocationhandler; import java.lang.reflect.method; import java.lang.reflect.proxy; import com.cignacmc.finance.bean.userBeanImpl; classe publique UserBeanProxy implémente invocationHandler {private Object TargetObject; public userbeanproxy (objet TargetObject) {this.targetObject = TargetObject; } public Object Invoke (Object Proxy, Method Method, Object [] args) lève le throwable {userbeanImpl userbean = (userbeanImpl) TargetObject; String username = userbean.getUserName (); Résultat de l'objet = null; // Jugement d'autorisation if (nom d'utilisateur! = Null &&! "". Equals (nom d'utilisateur)) {result = méthode.invoke (TargetObject, args); } Retour Résultat; }}
Classe de test
import java.lang.reflect.proxy; import com.cignacmc.finance.bean.userbean; import com.cignacmc.finance.bean.userBeanImpl; import com.cignacmc.finance.proxy.userbeanproxy; classe publique Proxyexe {public static void main (String [] args) {System.out.println ("Prouver ........."); UserbeanImpl TargetObject = new UserbeanImpl ("Bob Liang"); UserBeanProxy Proxy = new UserBeanProxy (TargetObject); // Générer l'objet proxy userbean object = (userbean) proxy.newproxyinstance (targetObject.getClass (). GetClassLoader (), TargetObject.getClass (). GetInterfaces (), proxy); object.adDuser (); System.out.println ("Non prouvé ............"); TargetObject = new UserbeanImpl (); proxy = new UserBeanProxy (TargetObject); // Générer l'objet Proxy Object = (Userbean) proxy.newproxyinstance (targetObject.getClass (). GetClassLoader (), TargetObject.getClass (). GetInterfaces (), proxy); object.adDuser (); }}
Sortir:
Prouver ............ Il s'agit de la méthode addUser ()! Non prouvé ..........
À partir de l'exemple ci-dessus, la méthode appelée addUser () peut être interceptée avec succès et traitée en conséquence.
2. Créez une classe proxy via CGLIB
L'avantage est que notre objet cible ne nécessite pas que la classe primitive de l'interface soit implémentée.
classe publique ClientBean {private String name = null; public ClientBean () {} public ClientBean (String Name) {this.name = name; } public void addClient () {System.out.println ("Ceci est addClient () Méthode!"); } public void DeleteClient () {System.out.println ("This is DeleteClient () Method!"); } public void getClient () {System.out.println ("This is GetClient () Method!"); } public void getClient () {System.out.println ("This is GetClient ()) Method!"); } public void updateClient () {System.out.println ("Ceci est UpdateClient () Méthode!"); } public String getClientName () {Nom de retour; } public void setClientName (String name) {this.name = name; }} Classe d'agent
import java.lang.reflect.method; import com.cignacmc.finance.bean.clientbean; importer net.sf.cglib.proxy.enhancer; importer net.sf.cglib.proxy.MethodInterceptor; importer net.sf.cglib.proxy.MethodInterceptor; importer net.sf.cglib.proxy.methodproxy; La classe publique CGLIBProxy implémente MethodInterceptor {Private Object TargetObject; public objet createProxyObject (objet TargetObject) {this.targetObject = TargetObject; Enhancer Enhancer = New Enhancer (); Enhancer.SetSuperclass (this.targetObject.getClass ()); Enhancer.setCallback (this); return Enhancer.Create (); } public Object Intercept (Proxy d'objet, méthode de la méthode, objet [] args, méthodyProxy methodproxy) lève throwsable {clientBean clientBean = (clientBean) TargetObject; String username = clientBean.getClientName (); Résultat de l'objet = null; if (username! = null &&! "". equals (nom d'utilisateur)) {result = méthode.invoke (targetObject, args); } Retour Résultat; }} Classe de test
import java.lang.reflect.proxy; import com.cignacmc.finance.bean.clientbean; import com.cignacmc.finance.bean.userbean; import com.cignacmc.finance.bean.userBeanImpl; import com.cignacmc.finance.proxy.cglibproxy; import com.cignacmc.finance.proxy.userbeanproxy; classe publique proxyexe {public static void main (String [] args) {System.out.println ("........ proxy cglib ............"); System.out.println ("prouvé ..............."); Cglibproxy cproxy = nouveau cglibproxy (); ClientBean ClientBean = (ClientBean) cProxy.CreateProxyObject (new ClientBean ("Bob Liang")); clientBean.AddClient (); System.out.println ("Non prouvé ..............."); cproxy = new cglibproxy (); ClientBean = (ClientBean) cProxy.CreateProxyObject (new ClientBean ()); clientBean.AddClient (); }}
Sortir:
..... CGLIB Proxy .................. prouvé ............ Il s'agit de la méthode addClient ()! Pas prouvé ............