Le concept de AOP
AOP: Programmation orientée vers l'aspect (programmation orientée sectionnelle), Wikipedia l'explique comme suit: l'aspect est un nouveau mécanisme modulaire utilisé pour décrire les préoccupations transversales diffusées dans des objets, des classes ou des fonctions. La séparation des préoccupations transversales des préoccupations est le concept principal de la programmation tangente. La séparation de l'attention rend le code qui résout des problèmes de domaine spécifiques indépendamment de la logique métier. Le code de logique métier ne contient pas d'appels à coder pour des problèmes de domaine spécifiques. La relation entre la logique métier et les problèmes de domaine spécifiques est encapsulée et maintenue à travers des sections, de sorte que les changements qui ont été dispersés à l'origine dans toute l'application peuvent être bien gérés. Du point de vue de l'AOP, les applications peuvent être divisées en préoccupations transversales et code logique métier. Dans le développement réel, ces préoccupations transversales sont souvent directement intégrées dans le code de la logique métier. La programmation axée sur le visage consiste à résoudre le problème de la séparation des préoccupations transversales de la logique métier.
Méthode d'implémentation:
Spring utilise le proxy dynamique JDK comme proxy d'AOP par défaut. La faille est que la classe cible doit implémenter une interface, sinon le proxy dynamique JDK ne peut pas être utilisé. Si la classe est une classe plutôt qu'une interface, Spring utilisera le proxy CGLIB par défaut. En ce qui concerne la différence entre les deux: le proxy dynamique JDK est implémenté via le mécanisme de réflexion de Java, la classe cible doit implémenter les interfaces et CGLIB implémente le proxy pour les classes. Son principe est de générer dynamiquement une sous-classe pour la classe cible spécifiée et de remplacer l'amélioration de l'implémentation de la méthode, mais parce que l'héritage est utilisé, la classe modifiée finale ne peut pas être proxyée.
Proxy dynamique JDK
JDK Dynamic Proxy génère dynamiquement des fichiers de classe de classes proxy basées sur l'interface implémentée par la classe cible pendant l'opération du programme. L'utilisation implique principalement deux classes:
Interface InvocationHandler: il fournit une méthode invoke(Object obj,Method method, Object[] args) pour les implémentateurs pour fournir l'implémentation de logique proxy correspondante. Un traitement spécial peut être effectué sur l'implémentation réelle, et les paramètres sont
Objet obj: la classe cible qui est procassée
Méthode Méthode: Méthode de la classe cible qui doit être exécutée
Objet [] args: paramètres de la méthode cible
Classe de proxy: Fournissez une méthode newProxyInstance (ClassLoader loader, Class[] interfaces, InvocationHandler h) Pour obtenir une classe de proxy dynamique
Exemple de code:
Interface publique OrderService {public void createOrder (); } classe publique OrderServiceIMPl implémente OrderService {@Override public void createOrder () {System.out.println ("Création de l'ordre"); }} classe publique OrderLogger {public void beForeCreateOrder () {System.out.println ("avant créer l'ordre"); } public void AfterCreateOrder () {System.out.println ("après créer l'ordre"); }} package com.sl.aop; import java.lang.reflect.invocationhandler; import java.lang.reflect.method; import java.lang.reflect.proxy; public class ServiceProxy implémente invocationhandler {private Object TargetClass; Private OrderLogger OrderLogger; public ServiceProxy (objet TargetClass, OrderLogger OrderLogger) {this.targetClass = TargetClass; this.OrderLogger = OrderLogger; } // Obtenez un objet public proxy getDamicProxy () {return proxy.newproxyinstance (targetclass.getClass (). GetClassLoader (), // Créer un objet proxy via cette classe Classloader. // La méthode de l'appel proxy dynamique est l'association invocationhandler et exécute enfin la méthode réelle via la méthode invoquée de cette invocationHandler} // implémenter la logique proxy correspondante @Override public objet invoke (objet proxy, méthode de la méthode, objet [] args) lance throwable {this.orderLogger.BefreatEorder (); Objet résultat = méthode.invoke (TargetClass, args); this.OrderLogger.AfterCreateOrder (); Résultat de retour; }}Classe de test:
package com.sl.aop; import org.junit.test; classe publique aoptest {@test public void testDynamicProxy () {OrderServiceImpl ServiceImpl = new OrderServiceIMPl (); OrderLogger logger = new OrderLogger (); ORDERSERVICE Service = (OrderService) Nouveau ServiceProxy (ServiceImpl, Logger) .getDynamicProxy (); Service.CreateOrder (); }}Résultats en cours:
Je suis en fait un peu confus quand j'arrive à ce point. Que renvoie Proxy.newProxyInstance() ? Où s'appelle la méthode invoquée? Jetons un coup d'œil au code source JDK: voyez à quoi ressemble le processus de proxy dynamique DK:
Appeler Proxy.newProxyInstance()->Proxy.getProxyClass0()->WeakCache.get() en fonction de la fonction à l'intérieur du code source, et la localisez d'abord
Faiblecache.class:
public v get (k key, p paramètre) {objets.RequiRenonnull (paramètre); expungestalentries (); Objet cacheKey = cacheKey.ValueOf (key, RefQueue); // Installez paresseusement le 2e niveau ValuesMap pour le Cachekey particulier 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) {// Le fournisseur peut être une usine ou une cachevalue <v> instance v valeur = 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) // construire paresseusement une usine if (factory == null) {factory = new factory (clé, paramètre, sous-mary, valeurs); } if (fournisseur == null) {fournisseur = valeursmap.putifabsent (subkey, usine); if (fournisseur == null) {// Installé avec succès fournisseur d'usine = usine; } // else réessayer avec le fournisseur gagnant} else {if (valeursmap.replace (sous-clé, fournisseur, usine)) {// remplacé avec succès // cacheentrie effacée / usine infructueuse // par notre fournisseur d'usine = usine; } else {// Reryant avec le fournisseur actuel fournisseur fournisseur = valeursmap.get (subkey); }}}} Vous pouvez voir la valeur de retour de la fonction; et V value = supplier.get(); Continuez à le lire et constatez que Supper = Factory est en fait un objet d'usine, alors continuez à afficher Factory.get()
public synchronisé v get () {// Serialize Access // re-cocher le fournisseur <v> fournisseur = valeursmap.get (subkey); si (fournisseur! = this) {// Quelque chose a changé pendant que nous attendions: // pourrait être que nous avons été remplacés par une cachevalue // ou nous avons été supprimés en raison de l'échec -> // retour null pour signaler faiblesCache.get () pour réessayer // la boucle retourne null; } // else toujours us (fournisseur == ceci) // Créer une nouvelle valeur V valeur V = null; try {value = object.requireNonnull (valuefactory.Apply (clé, paramètre)); } enfin {if (value == null) {// Supprimez-nous sur les valeurs de défaillancemap.remove (subkey, this); }} // Le seul chemin à atteindre ici est avec la valeur non nulle de valeur! = null; // Valeur enveloppe avec cachevalue (faible référence) cachevalue <v> cachevalue = new cachevalue <> (valeur); // Essayez de nous remplacer par une cachevalue (cela devrait toujours réussir) if (valeursmap.replace (subkey, this, cachevalue)) {// put également dans reversemap reversemap.put (cachevalue, boolean.true); } else {lancer une nouvelle assertionError ("ne devrait pas atteindre ici"); } // nous a remplacés avec succès par une nouvelle cachevalue -> Renvoie la valeur // enveloppée par la valeur de retour de celui-ci; } Valeur de retour; puis affichez directement l'instruction Affectation: value = Objects.requireNonNull(valueFactory.apply(key, parameter));
Qu'est-ce qui est ValueFactory?
public faibleCache (bifonction <k, p ,?> subkeyfactory, bifunction <k, p, v> valuefactory) {this.subKeyFactory = objets.requireNonnull (subkyfactory); this.valuefactory = objets.RequiRenonnull (valeurfactory); } private static final faiblecache <classloader, class <?> [], class <? >> proxyClassCache = new faiblecache <> (new KeyFactory (), new proxyClassFactory ()); Vous pouvez savoir que ValueFactory est un objet de type ProxyclassFactory et afficher directement ProxyClassFactory. Apply() Méthode ProxyClassFactory. Apply()
public class <?> appliquer (classloader chargeur, class <?> [] interfaces) {map <class <?>, booléan> interfaceset = new identityhashmap <> (interfaces.length); pour (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; try {interfaceClass = class.forname (intf.getName (), false, loder); } catch (classNotFoundException e) {} if (interfaceClass! = intf) {throw new illégalargumentException (intf + "n'est pas visible de la classe de classe"); } / * * Vérifiez que l'objet de classe représente en fait une interface *. * / if (! interfaceClass.isInterface ()) {Throw new illégalArgumentException (interfaceClass.getName () + "n'est pas une interface"); } / * * Vérifiez que cette interface n'est pas un double. * / 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 int AccessFlags = modificateur.public | Modificateur.Final; / * * 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. * / for (class <?> intf: interfaces) {int flags = intf.getModifiers (); if (! Modifier.ispublic (flags)) {AccessFlags = modificateur.Final; 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 (); String proxyname = proxyPkg + proxyclassNamePrefix + num; / * * Générez la classe proxy spécifiée. * / byte [] proxyClassFile = proxygenerator.generateProxyclass (proxyname, interfaces, accessFlags); essayez {return deficlass0 (chargeur, proxyname, proxyClassFile, 0, proxyClassFile.length); } catch (classformaterror e) {/ * * Un classformaterror signifie que (sauf bogues dans le * code de génération de classe proxy) il y avait un autre aspect * non valide des arguments fournis à la création de classe proxy * (tels que les limitations virtuelles de la machine * dépassée). * / lancer un nouveau IllégalArgumentException (e.toString ()); }}}Dessinez directement les points clés:
octet [] proxyClassFile = proxygenerator.GENERETERPROXYCLASS (proxyname, interfaces, AccessFlags); return Deficlass0 (chargeur, proxyname, proxyClassFile, 0, proxyClassFile.length);
Appeler ProxyGenerator.generateProxyClass génère finalement dynamiquement une classe de proxy, mais il semble que nulle part ne se trouve que c'est appelé invoke; Reportez-vous à l'article CSDN: //www.vevb.com/article/118935.htm, essayez de sortir le bytecode binaire généré dynamiquement localement et de le décompiler pour voir de quoi il s'agit. Le code de test est le suivant:
classe publique aopTest {@Test public void testDynamicProxy () {OrderServiceImpl ServiceImpl = new OrderServiceImpll (); OrderLogger logger = new OrderLogger (); ORDERSERVICE Service = (OrderService) Nouveau ServiceProxy (ServiceImpl, Logger) .getDynamicProxy (); Service.CreateOrder (); // Sortie de classe proxy dynamique bytecode createProxyclassFile (); } private static void createProxyClassFile () {String name = "proxyObject"; Byte [] data = proxygenerator.generateProxyclass (name, new class [] {orderService.class}); FileoutputStream out = null; try {out = new FileOutputStream (name + ". class"); System.out.println ((nouveau fichier ("Hello")). GetAbsoluTepath ()); out.write (données); } catch (filenotFoundException e) {e.printStackTrace (); } catch (ioException e) {e.printStackTrace (); } enfin {if (null! = out) try {out.close (); } catch (ioException e) {e.printStackTrace (); }}}}}}Utilisez l'outil de décompilateur Java pour décompiler ce fichier de classe binaire:
Classe proxy dynamique spécifique proxyObject.java:
Importer com.sl.aop.orderservice; import java.lang.reflect.invocationhandler; import java.lang.reflect.method; import java.lang.reflect.proxy; import java.lang.reflect.undeclatedthrowableException; Private class proxyobject extend proxy implete les ordres des services de service privé; Méthode statique privée M2; Méthode statique privée M3; Méthode statique privée M0; public proxyObject (invocationHandler paraminvocationhandler) {super (paraminvocationhandler); } public final boolean equals (objet paramobject) {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 string toString () {try {return (string) this.h.invoke (this, m2, null); } catch (error | runtimeException localerror) {throw localerror; } catch (landable localthrowable) {lancez un nouveau UnclaredThrowableException (localthrowable); }} public final void createOrder () {try {this.h.invoke (this, m3, null); retour; } catch (error | runtimeException localerror) {throw localerror; } catch (landable localthrowable) {lancez un nouveau UnclaredThrowableException (localthrowable); }} public final int hashcode () {try {return ((Integer) this.h.invoke (this, m0, null)). intValue (); } catch (error | runtimeException localerror) {throw localerror; } catch (landable localthrowable) {lancez un nouveau UnclaredThrowableException (localthrowable); }} static {try {m1 = class.forname ("java.lang.object"). getMethod ("equals", new class [] {class.forname ("java.lang.object")}); m2 = class.forname ("java.lang.object"). getMethod ("toString", new class [0]); m3 = class.forname ("com.sl.aop.orderservice"). getMethod ("CreateOrder", new class [0]); m0 = class.forname ("java.lang.object"). getMethod ("hashcode", new class [0]); retour; } catch (NosuchMethodexception localNosuchMethodexception) {lance un nouveau NoSuchMethoDerror (localNosuchMethodexception.getMessage ()); } catch (classNotFoundException localClassNotFoundException) {lancer un nouveau noclassDEffoundError (localClassNotFoundException.GetMessage ()); }}Enfin vu la partie sur Invoke:
public final void createOrder () {try {this.h.invoke (this, m3, null); retour; } catch (error | runtimeException localerror) {throw localerror; } catch (landable localthrowable) {lancez un nouveau UnclaredThrowableException (localthrowable); }}En fait, la classe de proxy dynamique hérite de proxy et implémente l'interface héritée par la classe cible. La méthode invoquée est appelée dans la méthode CreateOrder, qui met en œuvre l'implantation de la logique sectionnelle. Ici, nous répondons également à une question, pourquoi la classe cible du proxy dynamique JDK doit implémenter l'interface, car la classe de proxy est en fait destinée au proxy d'interface, pas à la classe. La classe de proxy dynamique se hérite de proxy, et Java ne permet pas l'héritage multiple. La classe de proxy dynamique et la classe cible implémentent respectivement les interfaces respectivement. La classe Proxy réalise l'appel à la méthode de la classe cible via invocationhandler.invoke.
Proxy dynamique CGLIB
Le proxy CGLIB utilise un framework de traitement bytecode ASM pour convertir des bytecode et générer de nouvelles classes, et utilise des techniques d'interception de méthode dans les sous-classes pour intercepter toutes les méthodes de classe parent pour implémenter la logique de réduction croisée, ce qui est plus efficace que le proxy dynamique JDK en utilisant la technologie de réflexion. Cependant, comme le principe de CGLIB est de générer dynamiquement des classes proxy de sous-classe pour la classe cible, il ne peut pas être proxyé pour les méthodes déclarées finales. Son utilisation implique principalement deux catégories:
Interface MethodInterceptor: cette interface fournit une intercept(Object arg0, Method arg1, Object[] arg2, MethodProxy arg3) principalement utilisé pour intercepter l'appel des méthodes de classe cible.
Objet arg0 ,: La classe cible qui est procassée
Méthode Arg1, méthode déléguée
Objet [] arg2, paramètres de la méthode
MethodProxy Arg3: Méthodproxy Objet de la méthode proxy
Classe Enhancer: Utilisé pour créer une classe proxy
Exemple:
Implémentez l'interface MethodInterceptor. Lorsque la classe proxy appelle une méthode, CGLIB rappellera la méthode d'interception de l'interface MethodInterceptor, tissant ainsi la logique de surface.
package com.sl.aop; import java.lang.reflect.method; import org.springframework.cglib.proxy.enhancer; import org.springframework.cglib.proxy.methodinterceptor; import org.springframework.cglib.proxy.methodproxy; implémente MethodInterceptor {Private Object TargetClass; Private OrderLogger OrderLogger; public cglibServiceProxy (objet TargetClass, OrderLogger OrderLogger) {this.targetClass = TargetClass; this.OrderLogger = OrderLogger; } / ** * Créer un objet proxy * * / objet public getInstance () {Enhancer Enhancer = new Enhancer (); // Définissez la classe cible (classe qui doit être proxyed) Enhancer.SetSuperclass (this.targetClass.getClass ()); // Méthode de rappel Enhancer.SetCallback (this); // Créer un retour d'objet proxy Enhance.create (); } / ** * Intercepter toutes les méthodes de classe cible * * / @Override Public Object Intercept (objet Arg0, méthode arg1, objet [] arg2, methodproxy arg3) lance throwable {orderLogger.beforeCreateOrder (); Objet o1 = arg3.Invokesuper (arg0, arg2); OrderLogger.AfterCreateOrder (); retour o1; }}Méthode de test:
public void testDamicProxy () {System.SetProperty (DebuggingClasswriter.debug_location_property, "d: // class"); ORDERSERVICEIMPL SERVICEIMPL = NOUVEAU ORDERSERVICEIMPL (); OrderLogger logger = new OrderLogger (); CGLIBSERVICEPROXY Proxy = nouveau CglibServiceProxy (ServiceImpl, logger); // Créez une classe proxy en générant des sous-classes OrderServiceImpl proxyImp = (OrderServiceImpl) proxy.getInstance (); proxyimp.createOrder (); }résultat:
System.setProperty(DebuggingClassWriter.DEBUG_LOCATION_PROPERTY, "D://class"); Sortir la classe de proxy dynamique CGLIB au répertoire spécifié, décompiler et vérifier la vraie face de la classe proxy:
package com.sl.aop; import com.sl.aop.orderserviceImpl; import java.lang.reflect.method; import org.springframework.cglib.core.reflectUtils; import org.springframework.cglib.core.signature; import org.springframework.cglib.proxy.callback; Importation; org.springframework.cglib.proxy.factory; import org.springframework.cglib.proxy.methodInterceptor; import org.springframework.cglib.proxy.methodproxy; Classe publique OrderserviceImpl Boolean privé cglib $ bound; objet statique public cglib $ factory_data; Final Final statique privé Cglib $ thread_callbacks; rappel final statique privé [] cglib $ static_callbacks; Private MethodInterceptor cglib $ callback_0; objet statique privé cglib $ callback_filter; Méthode finale statique privée cglib $ createOrder 0 $ méthode; Méthode finale statique privée proxy cglib $ createOrder 0 $ proxy; objet final statique privé [] cglib $ videArgs; Méthode finale statique privée CGLIB $ équivaut à 1 $ Méthode; Méthode finale statique privée Cglib $ est équivalente à 1 $ de proxy; Méthode finale statique privée cglib $ tostring 2 $ méthode; Méthode finale statique privée Proxy cglib $ toString 2 $ proxy; Méthode finale statique privée cglib $ hashcode 3 $ méthode; Méthode finale statique privée PROXY CGLIB $ HASHCODE 3 $ Proxy; Méthode finale statique privée Clone $ Clone 4 $ Méthode; Méthode finale statique privée Proxy CGLIB $ clone 4 $ Proxy; statique void cglib $ statichook1 () {cglib $ thread_callbacks = new ThreadLocal (); Cglib $ videargs = nouvel objet [0]; Classe var0 = class.forname ("com.sl.aop.orderservicempl $$ EnhancerByCglib $$ 17779aa4"); Classe var1; Méthode [] var10000 = réflectutils.findMethods (new String [] {"equal Class.forname ("java.lang.object")). GetDeclaredMethods ()); CGLIB $ équivaut à 1 $ méthode = var10000 [0]; Cglib $ équivaut à 1 $ proxy = methodproxy.create (var1, var0, "(ljava / lang / objet;) z", "équivaut", "cglib $ équivaut à 1 $"); CGLIB $ toString 2 $ méthode = var10000 [1]; Cglib $ toString $ 2 $ proxy = methodproxy.create (var1, var0, "() ljava / lang / string;", "toString", "cglib $ tostring $ 2"); CGLIB $ HashCode 3 $ méthode = var10000 [2]; Cglib $ hashcode 3 $ proxy = methodproxy.create (var1, var0, "() i", "hashcode", "cglib $ hashcode 3"); CGLIB $ clone 4 $ méthode = var10000 [3]; Cglib $ clone 4 $ proxy = méthodeproxy.create (var1, var0, "() ljava / lang / objet;", "clone", "cglib $ clone 4"); Cglib $ createOrder $ 0 $ method = refleftoutils.findMethods (new String [] {"CreateOrder", "() v"}, (var1 = class.forname ("com.sl.aop.orderServiceImpl")). GetDeclaredMethods ()) [0]; Cglib $ createOrder 0 $ proxy = méthodeproxy.create (var1, var0, "() v", "createOrder", "cglib $ createOrder 0"); } final void cglib $ createOrder 0 () {super.createOrder (); } public final void CreateOrder () {MethodInterceptor var10000 = this.cglib $ callback_0; if (this.cglib $ callback_0 == null) {cglib $ bind_callbacks (this); var10000 = this.cglib $ callback_0; } if (var10000! = null) {var10000.intercept (this, cglib $ createOrder 0 $ méthode, cglib $ videargs, cglib $ createOrder 0 $ proxy); } else {super.createOrder (); }} final booléen cglib $ est égal à 1 $ (objet var1) {return super.equals (var1); } public final booléen equals (objet var1) {MethodInterceptor var10000 = this.cglib $ callback_0; if (this.cglib $ callback_0 == null) {cglib $ bind_callbacks (this); var10000 = this.cglib $ callback_0; } if (var10000! = null) {objet var2 = var10000.Intercept (this, cglib $ équivaut à 1 $ méthode, nouvel objet [] {var1}, cglib $ équivaut à 1 $ proxy); return var2 == null? false: ((boolean) var2) .booleanValue (); } else {return super.equals (var1); }} chaîne finale cglib $ toString $ 2 () {return super.toString (); } public final String toString () {MethodInterceptor var10000 = this.cglib $ callback_0; if (this.cglib $ callback_0 == null) {cglib $ bind_callbacks (this); var10000 = this.cglib $ callback_0; } return var10000! = null? (String) var10000.Intercept (this, cglib $ toString 2 $ méthode, cglib $ videargs, cglib $ toString $ proxy): super.toString (); } final int cglib $ hashcode 3 () {return super.hashcode (); } public final int hashcode () {méthodyInterceptor var10000 = this.cglib $ callback_0; if (this.cglib $ callback_0 == null) {cglib $ bind_callbacks (this); var10000 = this.cglib $ callback_0; } if (var10000! = null) {objet var1 = var10000.intercept (this, cglib $ hashcode 3 $ méthode, cglib $ videargs, cglib $ hashcode 3 $ proxy); return var1 == null? 0: ((nombre) var1) .IntValue (); } else {return super.hashcode (); }} objet final cglib $ clone $ () lève ClonenotsupportEdException {return super.clone (); } objet final protégé clone () lève ClonenotsupportEdException {MethodInterceptor var10000 = this.cglib $ callback_0; if (this.cglib $ callback_0 == null) {cglib $ bind_callbacks (this); var10000 = this.cglib $ callback_0; } return var10000! = null? var10000.intercept (this, cglib $ clone 4 $ méthode, cglib $ videargs, cglib $ clone 4 $ proxy): super.clone (); } Public Static MethodProxy cglib $ findMethodProxy (signature var0) {String var10000 = var0.toString (); commutateur (var10000.hashcode ()) {case -2138148221: if (var10000.equals ("CreateOrder () v")) {return cglib $ createOrder 0 $ proxy; } casser; cas -508378822: if (var10000.equals ("clone () ljava / lang / objet;")) {return cglib $ clone $ 4 $ proxy; } casser; Cas 1826985398: if (var10000.equals ("égaux (ljava / lang / objet;) z")) {return cglib $ équivaut à 1 $ proxy; } casser; cas 1913648695: if (var10000.equals ("toString () ljava / lang / string;"))) {return cglib $ toString 2 $ proxy; } casser; Case 1984935277: if (var10000.equals ("hashcode () i")) {return cglib $ hashcode 3 $ proxy; }} return null; } Public OrderServiceIMPL $$ EnhancerByCglib $$ 17779AA4 () {cglib $ bind_callbacks (this); } public static void cglib $ set_thread_callbacks (callback [] var0) {cglib $ thread_callbacks.set (var0); } public static void cglib $ set_static_callbacks (callback [] var0) {cglib $ static_callbacks = var0; } private static final void cglib $ bind_callbacks (objet var0) {OrderServiceImpl $$ EnhancerByCGlib $$ 1779aaa4 var1 = (ORDERSERVICEIMPL $$ EnhancerByCGIB $$ 17779AA4) VAR0; if (! var1.cglib $ bound) {var1.cglib $ bound = true; Objet var10000 = cglib $ thread_callbacks.get (); if (var10000 == null) {var10000 = cglib $ static_callbacks; if (cglib $ static_callbacks == null) {return; }} var1.cglib $ callback_0 = (méthodeInterceptor) ((callback []) var10000) [0]; }} Objet public NewInstance (callback [] var1) {cglib $ set_thread_callbacks (var1); ORDERSERVICEIMPL $$ EnhancerByCglib $$ 17779AA4 VAR10000 = NOUVEAU ORDERSERVICEIMPL $$ EnhancerByCglib $$ 17779AA4 (); Cglib $ set_thread_callbacks ((callback []) null); return var10000; } Objet public NewInstance (callback var1) {cglib $ set_thread_callbacks (nouveau callback [] {var1}); ORDERSERVICEIMPL $$ EnhancerByCglib $$ 17779AA4 VAR10000 = NOUVEAU ORDERSERVICEIMPL $$ EnhancerByCglib $$ 17779AA4 (); Cglib $ set_thread_callbacks ((callback []) null); return var10000; } Objet public NewInstance (class [] var1, objet [] var2, callback [] var3) {cglib $ set_thread_callbacks (var3); ORDERSERVICEIMPL $$ EnhancerByCglib $$ 17779AA4 VAR10000 = NOUVEAU ORDERSERVICEIMPL $$ EnhancerByCglib $$ 17779AA4; switch (var1.length) {case 0: var10000. <init> (); Cglib $ set_thread_callbacks ((callback []) null); return var10000; Par défaut: lancez un nouveau IllégalArgumentException ("Constructeur introuvable"); }} Public Callback getCallback (int var1) {cglib $ bind_callbacks (this); MethodInterceptor var10000; switch (var1) {case 0: var10000 = this.cglib $ callback_0; casser; par défaut: var10000 = null; } return var10000; } public void setCallback (int var1, callback var2) {switch (var1) {case 0: this.cglib $ callback_0 = (méthodeInterceptor) var2; Default:}} public callback [] getCallbacks () {cglib $ bind_callbacks (this); return nouveau rappel [] {this.cglib $ callback_0}; } public void setCallbacks (callback [] var1) {this.cglib $ callback_0 = (methodInterceptor) var1 [0]; } statique {cglib $ statichook1 (); }}Dans le code ci-dessus, vous pouvez voir que la classe de procuration OrderServiceImpl $$ EnhancerByCglib $$ 17779AA4 hérite de la classe cible OrderServiceImpll et implémente l'usine d'interface. Dans la classe de proxy, deux méthodes CGLIB $ CREATORORDER 0 $ et CreateOrder sont générées:
La méthode CGLIB $ CREATEDORDERSORD 0 $ appelle directement le supper.createOrder de la classe cible. Création
La méthode CreateOrder compte d'abord si le rappel de l'interface MethodInterceptor est implémenté. S'il existe, la méthode d'interception d'interface MethodInterceptor est appelée. Selon l'implémentation précédente, l'appel à la méthode cible est implémenté. Object o1 = arg3.invokeSuper(arg0, arg2) est implémenté. L'Invokesuper est en fait CGLIB$createOrder$0() de la classe de proxy qui est directement appelée, et la classe cible CreateOrder est finalement appelée.
Comparaison de deux agents
JDK Dynamic Proxy:
La classe proxy et la classe de délégués implémentent la même interface. Il implémente principalement l'invocationHandler via la classe de proxy et réécrit la méthode invoquée pour effectuer un proxyage dynamique. La méthode sera améliorée dans la méthode invoquée. Les avantages de la méthode: aucune interface à code dur n'est requise et le taux de réutilisation du code est élevé. Inconvénients: seule la classe du délégué qui peut être implémentée par l'interface
Proxy dynamique CGLIB:
La classe proxy prend la classe de délégués comme classe parent et crée deux méthodes pour les méthodes de délégué non finale. L'une est la même méthode que la signature de la méthode du délégué, qui appellera la méthode du délégué via Super dans la méthode; L'autre est la méthode unique à la classe proxy. Dans la méthode proxy, il déterminera s'il existe un objet qui implémente l'interface MethodInterceptor. S'il existe, la méthode d'interception sera appelée pour procurer la méthode du délégué. Avantages: il peut améliorer le fonctionnement de la classe ou de l'interface au moment de l'exécution, et la classe de délégué n'a pas besoin d'implémenter l'interface. Inconvénients: il ne peut pas procurer la classe finale et la méthode finale.
Résumer
Ce qui précède est l'intégralité du contenu de cet article. J'espère que le contenu de cet article a une certaine valeur de référence pour l'étude ou le travail de chacun. Si vous avez des questions, vous pouvez laisser un message pour communiquer. Merci pour votre soutien à wulin.com.