El concepto de AOP
AOP: Programación orientada al aspecto (programación orientada a la sección), Wikipedia lo explica de la siguiente manera: el aspecto es un nuevo mecanismo modular utilizado para describir preocupaciones transversales dispersas en objetos, clases o funciones. Separar las preocupaciones transversales de las preocupaciones es el concepto central de programación orientada a tangentes. Separar el enfoque hace que el código que resuelva problemas de dominio específicos independientemente de la lógica de negocios. El código de la lógica comercial no contiene llamadas al código para problemas de dominio específicos. La relación entre la lógica empresarial y los problemas de dominio específicos se encapsula y se mantiene a través de secciones, por lo que los cambios que originalmente se dispersaron en toda la aplicación pueden administrarse bien. Desde la perspectiva de AOP, las aplicaciones se pueden dividir en preocupaciones transversales y código de lógica comercial. En el desarrollo real, estas preocupaciones transversales a menudo se integran directamente en el código de lógica de negocios. La programación orientada a la cara es resolver el problema de separar las preocupaciones transversales de la lógica empresarial.
Método de implementación:
Spring utiliza el proxy dinámico JDK como proxy de AOP por defecto. La falla es que la clase de destino debe implementar una interfaz, de lo contrario, el proxy dinámico JDK no se puede usar. Si la clase es una clase en lugar de una interfaz, Spring usará CGLIB proxy de forma predeterminada. Con respecto a la diferencia entre los dos: JDK Dynamic Proxy se implementa a través del mecanismo de reflexión de Java, la clase de destino debe implementar interfaces y CGLIB implementa proxy para las clases. Su principio es generar dinámicamente una subclase para la clase de destino especificada y anular la mejora de la implementación del método, pero debido a que se usa la herencia, la clase modificada final no puede ser proxyenada.
JDK proxy dinámico
JDK Dynamic Proxy genera dinámicamente archivos de clases de clases proxy basadas en la interfaz implementada por la clase de destino durante la operación del programa. El uso implica principalmente dos clases:
Interfaz Invocathandler: proporciona un método invoke(Object obj,Method method, Object[] args) para que los implementadores proporcionen la implementación de lógica proxy correspondiente. Se puede realizar algún procesamiento especial en la implementación real, y los parámetros son
Obj OBJ: la clase de destino que está proxyed
Método Método: método de la clase de destino que debe ejecutarse
Objeto [] args: parámetros del método de destino
Clase proxy: proporcione un método newProxyInstance (ClassLoader loader, Class[] interfaces, InvocationHandler h) para obtener una clase proxy dinámica
Código de muestra:
Public Interface OrderService {public void createOrder (); } Public Class OrderServiceImpl implementa OrderService {@Override public void createOrder () {System.out.println ("Creación de orden"); }} Public Class OrderLogger {public void beforecreateRoRorder () {System.out.println ("antes de crear orden"); } public void AfterCreateRoRorder () {System.out.println ("después de crear orden"); }} paquete com.sl.aop; import java.lang.reflect.invocationHandler; import java.lang.reflect.method; import java.lang.reflect.proxy; pública clase ServiceProxy implementa InvocationHandler {PRIVADO Object TargetClass; OrderLogger privado OrderLogger; Public ServiceProxy (Object TargetClass, OrderLogger OrderLogger) {this.targetClass = TargetClass; this.OrderLogger = OrderLogger; } // Get Proxy Public Object getDynamicProxy () {return proxy.newproxyInstance (TargetClass.getClass (). // El método de llamada de proxy dinámico es el InvocationHandler asociado, y finalmente ejecuta el método real a través del método Invoke de este InvocationHandler} // implementa la lógica proxy correspondiente @Override Public Object Invoke (Object Proxy, Method Method, Object [] Resultado del objeto = método.invoke (TargetClass, Args); this.OrderLogger.AfterCreateRoRorder (); resultado de retorno; }}Clase de prueba:
paquete com.sl.aop; import org.junit.test; public class aoptest {@test public void testDynamicProxy () {OrderServiceImpl ServiceImpl = new OrderServiceImpl (); OrderLogger logger = new OrderLogger (); OrderService Service = (OrderService) nuevo ServiceProxy (ServiceImpl, Logger) .getDynamicProxy (); servicio.createRoRord (); }}Resultados de ejecución:
De hecho, estoy un poco confundido cuando llego a este punto. ¿Qué regresa Proxy.newProxyInstance() ? ¿A dónde se llama el método de invoca? Echemos un vistazo al código fuente de JDK: vea cómo se ve el proceso de proxy dinámico DK:
Llame Proxy.newProxyInstance()->Proxy.getProxyClass0()->WeakCache.get() de acuerdo con la función dentro del código fuente, y primero lo ubíquelo
Débilcache.class:
public v get (k key, p parámetro) {objects.requirenonnull (parámetro); ExpungestaleEnries (); Objeto cachekey = cachekey.valueOf (clave, refQueue); // Instale perezosamente el nivel de valores de 2do nivel para el CacheKey particular concurrentMap <Object, Proveedor <v>> valores = map.get (cachekey); if (valueMap == null) {concurrentMap <object, proveedor <v>> oldValuesMap = map.putifabsent (cachekey, valoresmap = new concurrenthashmap <> ()); if (OldValuesMap! = NULL) {ValuesMap = OldValuesMap; }} // Crear subcepita y recuperar el posible proveedor <v> almacenado por eso // Subkey desde ValuesMap Object Subkey = Objects.RequirenonNull (SubkeyFactory.Apply (Key, Parameter)); Proveedor <v> proveedor = valoresmap.get (subpuesta); Fábrica de fábrica = nulo; while (true) {if (proveedor! = null) {// El proveedor podría ser una fábrica o una cachevalue <v> instancia v valor = proveedor.get (); if (value! = null) {value de retorno; }} // de lo contrario no hay proveedor en caché // o un proveedor que devolviera nulo (puede ser un cachevalue // o una fábrica que no tuvo éxito en la instalación del cachevalue) // construye perezosamente una fábrica if (factory == null) {fábrica = nueva fábrica (clave, parámetro, subprocesos, valores map); } if (proveedor == null) {proveedor = valoresmap.putifabsent (subpuesta, fábrica); if (proveedor == null) {// instalado con éxito fábrica proveedor = fábrica; } // de lo contrario vuelva a intentar con el proveedor ganador} else {if (valoresmap.replace (subproducción, proveedor, fábrica)) {// reemplazado con éxito // cacheEntry / fábrica sin éxito // con nuestro proveedor de fábrica = fábrica; } else {// Vuelva a intentar con el proveedor actual proveedor del proveedor = ValuesMap.get (Subkey); }}}} Puede ver el valor de retorno de la función; y V value = supplier.get(); Continúe leyéndolo y descubra que Supper = Factory es en realidad un objeto de fábrica, así que continúe viendo Factory.get()
public Synchronized v get () {// Serialize Access // Vuelva a verificar el proveedor <v> proveedor = ValuesMap.get (Subkey); if (proveedor! = this) {// Algo cambió mientras esperábamos: // podría ser que fuimos reemplazados por un Cachevalue // o fuimos eliminados debido a la falla -> // Devuelve nulo a señalar débilcache.get () para volver a intentar // el bucle return null; } // else Still Us (proveedor == this) // Crear nuevo valor v valor = null; intente {value = objects.requirenonnull (valueFactory.apply (clave, parámetro)); } Finalmente {if (value == null) {// eliminarnos en falla valores map.remove (subpuesta, esto); }} // La única ruta a alcanzar aquí es con valor de valor no nulo. // Valor de envoltura con Cachevalue (WeakReference) Cachevalue <V> Cachevalue = new Cachevalue <> (valor); // Intenta reemplazarnos con Cachevalue (esto siempre debería tener éxito) if (valueMap.replace (subprocesos, this, cachevalue)) {// poner también en reversemplop reversemp.put (cachevalue, boolean.true); } else {tirar nueva afirmación ("no debe alcanzar aquí"); } // Nos reemplazó con éxito con el nuevo CacheValue -> Devuelve el valor // Wraped by It Return Value; } Valor de retorno; Luego, vea directamente la declaración de asignación: value = Objects.requireNonNull(valueFactory.apply(key, parameter));
¿Qué diablos es valuefactory?
Public WeakCache (bifunción <k, p,?> SubkeyFactory, bifunción <k, p, v> valueFactory) {this.subkeyFactory = objects.requirenonnull (subkeyFactory); this.ValueFactory = Objects.RequirenonNull (valueFactory); } private static final débilcache <classloader, class <?> [], class <? >> proxyClassCache = new WeakCache <> (new KeyFactory (), new ProxyClassFactory ()); Puede saber que ValueFactory es un objeto de tipo proxyClassFactory y ver directamente ProxyClassFactory. Apply() método
clase pública <?> Aplicar (ClassLoader Loader, clase <?> [] interfaces) {map <class <?>, boolean> interfaceset = new IdentityHashMap <> (interfaces.length); for (clase <?> intf: interfaces) { / * * Verifique que el cargador de clase resuelva el nombre de esta interfaz * al mismo objeto de clase. */ Class <?> Interfaceclass = null; intente {interfaceClass = class.forname (intf.getName (), false, loader); } Catch (ClassNotFoundException e) {} if (interfaceclass! = intf) {throw new IlegalArGumentException (intf + "no es visible desde el cargador de clases"); } / * * Verifique que el objeto de clase realmente represente una interfaz *. */ if (! interfaceClass.isInterface ()) {throw newleArgumentException (interfaceClass.getName () + "no es una interfaz"); } / * * Verifique que esta interfaz no sea un duplicado. */ if (interfaceset.put (interfaceClass, boolean.true)! = null) {tirar nueva ilegalArGumentException ("Interfaz repetida:" + interfaceclass.getName ()); }} Cadena proxypkg = null; // paquete para definir la clase proxy en int accessflags = modifier.public | Modificador.final; / * * Registre el paquete de una interfaz proxy no pública para que la clase * proxy se define en el mismo paquete. Verifique que * todas las interfaces proxy no públicas estén en el mismo paquete. */ for (class <?> intf: interfaces) {int flags = intf.getModifiers (); if (! Modifier.ispublic (flags)) {AccessFlags = Modifier.Final; Name de cadena = intf.getName (); int n = name.lastIndexof ('.'); Cadena pkg = ((n == -1)? "": Name.substring (0, n + 1)); if (proxypkg == null) {proxypkg = pkg; } else if (! pkg.equals (proxypkg)) {arrojar nueva ilegalargumentException ("interfaces no públicas de diferentes paquetes"); }}}} if (proxypkg == null) {// Si no hay interfaces proxy no públicas, use com.sun.proxy paquete proxypkg = reflectUtil.proxy_package + "."; } / * * Elija un nombre para la clase proxy para generar. */ long num = nextUniqueNumber.getAndIncrement (); Cadena proxyname = proxypkg + proxyClassNamePrefix + num; / * * Genere la clase proxy especificada. */ byte [] proxyClassFile = proxyGenerator.GenerateProxyClass (proxyname, interfaces, accessflags); Pruebe {return DefinClass0 (cargador, proxyname, proxyClassFile, 0, proxyClassFile.length); } Catch (ClassFormaterror e) { / * * ClassFormaterror aquí significa que (salvo errores en el * código de generación de clases de proxy) había algún otro aspecto * inválido de los argumentos suministrados a la creación de clases proxy * (como las limitaciones de la máquina virtual * excedieron). */ tirar nueva ilegalArgumentException (e.ToString ()); }}}Dibuja directamente los puntos clave:
byte [] proxyClassFile = proxyGenerator.GenerateProxyClass (proxyname, interfaces, accessflags); return definicLass0 (cargador, proxyname, proxyClassfile, 0, proxyClassFile.length);
Llamar ProxyGenerator.generateProxyClass finalmente genera dinámicamente una clase de proxy, pero parece que no se llama a ninguna parte Invoke; Consulte el artículo csdn: //www.vevb.com/article/118935.htm, intente emitir el bytecode binario generado dinámicamente localmente y descompilarlo para ver qué es. El código de prueba es el siguiente:
public class Aoptest {@test public void testDynamicProxy () {OrderServiceImpl ServiceImpl = new OrderServiceImpl (); OrderLogger logger = new OrderLogger (); OrderService Service = (OrderService) nuevo ServiceProxy (ServiceImpl, Logger) .getDynamicProxy (); servicio.createRoRord (); // Salida Dynamic Proxy Clase Bytecode CreateProxyClassFile (); } private static void createProxyClassFile () {String name = "proxyObject"; byte [] data = proxyGenerator.GenerateProxyClass (nombre, nueva clase [] {OrderService.class}); FileOutputStream out = null; intente {out = new FileOutputStream (nombre+". Class"); System.out.println ((nuevo archivo ("hola")). GetAbSolutePath ()); out.write (datos); } catch (FileNotFoundException e) {E.PrintStackTrace (); } catch (ioException e) {E.PrintStackTrace (); } finalmente {if (null! = out) intente {out.close (); } catch (ioException e) {E.PrintStackTrace (); }}}}}}Use la herramienta Java Decompiler para descompilar este archivo de clase binaria:
Clase de proxy dinámica específica proxyObject.java:
import com.sl.aop.orderService; import java.lang.reflect.invocationHandler; import java.lang.reflect.method; import java.lang.reflect.proxy; import java.lang.reflect.undeClaredThrowableException; public Final Class ProxyObject extiende Proxy OrdersService {private static Method Method Method; Método estático privado M2; Método estático privado M3; Método estático privado M0; public proxyObject (InvocationHandler ParamInVocationHandler) {super (ParamInVocationHandler); } public final Boolean iguales (objeto ParamObject) {try {return ((boolean) this.h.invoke (this, m1, nuevo objeto [] {paramObject})). booleanValue (); } Catch (Error | RuntimeException localError) {lanzar localError; } Catch (lanzable localThrowable) {lanzar una nueva no defensa de la concepción (localThrowable); }} public Final String ToString () {try {return (string) this.h.invoke (this, m2, null); } Catch (Error | RuntimeException localError) {lanzar localError; } Catch (lanzable localThrowable) {lanzar una nueva no defensa de la concepción (localThrowable); }} public Final void createOrder () {try {this.h.invoke (this, m3, null); devolver; } Catch (Error | RuntimeException localError) {lanzar localError; } Catch (lanzable localThrowable) {lanzar una nueva no defensa de la concepción (localThrowable); }} public final int hashcode () {try {return ((integer) this.h.invoke (this, m0, null)). intValue (); } Catch (Error | RuntimeException localError) {lanzar localError; } Catch (lanzable localThrowable) {lanzar una nueva no defensa de la concepción (localThrowable); }} static {try {m1 = class.forname ("java.lang.object"). getMethod ("igual", nueva clase [] {class.forname ("java.lang.object")}); m2 = class.forname ("java.lang.object"). getMethod ("toString", nueva clase [0]); m3 = class.forname ("com.sl.aop.orderservice"). getMethod ("createOrder", nueva clase [0]); m0 = class.forname ("java.lang.object"). getMethod ("hashcode", nueva clase [0]); devolver; } Catch (nosuchmethodexception localNoSuchMethodException) {tire nuevo nosuchmethoderror (localnosuchmethodexception.getMessage ()); } Catch (ClassNotFoundException localClassNotFoundException) {lanzar newLassDefFoundError (localClassNotFoundException.getMessage ()); }}Finalmente vi la parte sobre Invoke:
public final void createerorder () {try {this.h.invoke (this, m3, null); devolver; } Catch (Error | RuntimeException localError) {lanzar localError; } Catch (lanzable localThrowable) {lanzar una nueva no defensa de la concepción (localThrowable); }}De hecho, la clase dinámica de proxy hereda del proxy e implementa la interfaz heredada por la clase de destino. El método de Invoke se llama en el método CreateOrder, que implementa la implantación de la lógica seccional. Aquí también respondemos una pregunta, por qué la clase objetivo del proxy dinámico JDK debe implementar la interfaz, porque la clase proxy está dirigida al proxy de la interfaz, no a la clase. La clase dinámica de proxy se hereda del proxy, y Java no permite la herencia múltiple. La clase proxy dinámica y la clase de destino realmente implementan las interfaces respectivamente. La clase proxy realiza la llamada al método de clase de destino a través de InvocationHandler.invoke.
Proxy dinámico CGLIB
El proxy de CGLIB utiliza un marco de procesamiento de bytecode ASM para convertir el código de bytecodo y generar nuevas clases, y utiliza técnicas de interceptación de métodos en subclases para interceptar todos los métodos de clase principal para implementar la lógica transversal, que es más eficiente que el proxy dinámico JDK utilizando tecnología de reflexión. Sin embargo, dado que el principio de CGLIB es generar dinámicamente las clases de proxy de subclase para la clase de destino, no puede ser proxyed para los métodos declarados como finales. Su uso implica principalmente dos categorías:
Interfaz MethodInterceptor: esta interfaz proporciona una intercept(Object arg0, Method arg1, Object[] arg2, MethodProxy arg3) utilizada principalmente para interceptar la llamada de los métodos de clase de destino.
Object Arg0,: la clase de destino que se está proxenando
Método arg1, método delegado
Objeto [] arg2, parámetros del método
MethodProxy Arg3: MethodProxy Object of Proxy Method
Clase potenciadora: se usa para crear clase proxy
Ejemplo:
Implemente la interfaz MethodInterceptor. Cuando la clase proxy llama a un método, CGLIB volverá a llamar al método de intercepción de interfaz de Methodinterceptor, tejiendo así la lógica de la superficie.
paquete com.sl.aop; import java.lang.reflect.method; import org.springframework.cglib.proxy.enhancer; import org.springframework.cglib.proxy.methodinterceptor; import org.springfrfframework.cglib.proxy.methodproxy; public class cglibservexypexypexypexypexypexypexypriceCtexypexypexypexypexypexypexypexypexypexypexypexypexypexypexypexypexypexypexypexypexypexypexypexypexypexypexypexypexypexypexypexy {Objeto privado TargetClass; OrderLogger privado OrderLogger; public cglibServiceProxy (Object TargetClass, OrderLogger OrderLogger) {this.TargetClass = TargetClass; this.OrderLogger = OrderLogger; } / *** Crear un objeto proxy** / Public Object getInStance () {mejor mejor potencador = new mejor (); // Establezca la clase de destino (clase que debe ser proxyed) potencer.setsuperClass (this.targetClass.getClass ()); // Método de devolución de llamada potencador.setCallback (esto); // Crear proxy Object Return MEVORACE.Create (); } / *** Intercepta todos los métodos de clase de destino** / @Override Public Object Intercept (Object Arg0, Method Arg1, Object [] Arg2, MethodProxy Arg3) lanza {OrderLogger.BeforCreateRoRorder (); Objeto o1 = arg3.invokesuper (arg0, arg2); OrderLogger.AfterCreateRoRord (); regreso O1; }}Método de prueba:
public void testDynamicProxy () {System.SetProperty (debuggingClassWriter.debug_location_property, "d: // class"); OrderServiceImpl ServiceImpl = new OrderServiceImpl (); OrderLogger logger = new OrderLogger (); CglibServiceProxy proxy = new CGLIBServiceProxy (ServiceImpl, Logger); // Crear una clase proxy generando subclases OrderserviceImpl proxyimp = (OrderServiceImpl) proxy.getInstance (); proxyimp.createRoRder (); }resultado:
System.setProperty(DebuggingClassWriter.DEBUG_LOCATION_PROPERTY, "D://class"); Clase de proxy dinámica de salida CGLIB al directorio especificado, descompilar y verificar la cara real de la clase proxy:
paquete 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. CGLIB $ Bound; Objeto estático público CGLIB $ factory_data; Private static final Threadlocal cglib $ thread_callbacks; devolución de llamada final estática privada [] cglib $ static_callbacks; Methodinterceptor privado CGLIB $ Callback_0; Objeto estático privado CGLIB $ Callback_filter; Método final estático privado cglib $ createorder $ 0 $ método; Método final estático privado proxy cglib $ createorder $ 0 $ proxy; Objeto final estático privado [] CGLIB $ vacíaCs; Método final estático privado CGLIB $ EQUALLA $ 1 $ Método; Método final estático privado Proxy CGLIB $ EQUILSA $ 1 $ proxy; Método final estático privado CGLIB $ ToString $ 2 $ Método; Método final estático privado Proxy CGLIB $ ToString $ 2 $ proxy; Método final estático privado CGLIB $ hashcode $ 3 $ método; Método final estático privado Proxy CGLIB $ hashcode $ 3 $ proxy; Método Final estático privado CLONE $ Clone $ 4 $ Método; Método final estático privado Proxy CGLIB $ Clone $ 4 $ proxy; static void cglib $ statichook1 () {cglib $ thread_callbacks = new ThreadLocal (); Cglib $ vacíaArgs = nuevo objeto [0]; Clase var0 = class.forname ("com.sl.aop.orderserviceImpl $$ Mentorbycglib $$ 17779AA4"); Clase VAR1; Método [] var10000 = reflectUtilss.FindMethods (new String [] {"iguales", "(lJava/Lang/Object;) z", "ToString", "() lJava/Lang/String;", "Hashcode", "() i", "clone", "() lJava/lang/objeto;"}, (var1, (var1, "() i", "clone", "() ljava/lang/objeto;"}, (var1, (var1, () Class.forname ("java.lang.object")). GetDeclaredMethods ()); Cglib $ es igual a $ 1 $ método = var10000 [0]; Cglib $ es igual a $ 1 $ proxy = MethodProxy.Create (var1, var0, "(ljava/lang/object;) z", "iguales", "cglib $ es igual a $ 1"); Cglib $ toString $ 2 $ método = var10000 [1]; Cglib $ toString $ 2 $ proxy = métodeProxy.create (var1, var0, "() ljava/lang/string;", "toString", "cglib $ toString $ 2"); Cglib $ hashcode $ 3 $ método = var10000 [2]; Cglib $ hashcode $ 3 $ proxy = métodeProxy.Create (var1, var0, "() i", "hashcode", "cglib $ hashcode $ 3"); Cglib $ clone $ 4 $ método = var10000 [3]; Cglib $ clone $ 4 $ proxy = MethodProxy.Create (var1, var0, "() ljava/lang/object;", "clon", "cglib $ clone $ 4"); Cglib $ createorder $ 0 $ método = reflectUtils.findMethods (new String [] {"CreateOrder", "() V"}, (var1 = class.forname ("com.sl.aop.orderserviceImpl")). GetDeclaredMethods () [0]; Cglib $ createOrder $ 0 $ proxy = métodeProxy.Create (var1, var0, "() v", "createOrder", "cglib $ createorder $ 0"); } final void cglib $ createorder $ 0 () {super.createRoRord (); } public final void createOrder () {MethodInterceptor Var10000 = this.cglib $ llamado Callback_0; if (this.cglib $ callback_0 == null) {cglib $ bind_callbacks (this); var10000 = this.cglib $ llamado Callback_0; } if (var10000! = null) {var10000.intercept (this, cglib $ createorder $ 0 $ $ Método, cglib $ vacungs, cglib $ createorder $ 0 $ proxy); } else {super.createRoRder (); }} final boolean cglib $ es igual a $ 1 (objeto var1) {return super.equals (var1); } public Final Boolean Equals (Object Var1) {MethodInterceptor Var10000 = this.cglib $ llamado Callback_0; if (this.cglib $ callback_0 == null) {cglib $ bind_callbacks (this); var10000 = this.cglib $ llamado Callback_0; } if (var10000! = null) {objeto var2 = var10000.intercept (this, cglib $ igual $ 1 $ método, nuevo objeto [] {var1}, cglib $ es igual a $ 1 $ proxy); return var2 == null? false: ((boolean) var2) .booleanValue (); } else {return super.equals (var1); }} cadena final cglib $ toString $ 2 () {return super.toString (); } public Final String ToString () {MethodInterceptor Var10000 = this.cglib $ llamado Callback_0; if (this.cglib $ callback_0 == null) {cglib $ bind_callbacks (this); var10000 = this.cglib $ llamado Callback_0; } return var10000! = null? (string) var10000.intercept (this, cglib $ toString $ 2 $ método, cglib $ vacungs, cglib $ toString $ 2 $ proxy): super.tostring (); } final int cglib $ hashcode $ 3 () {return super.hashcode (); } public final int hashcode () {MethodInterceptor Var10000 = this.cglib $ llamado Callback_0; if (this.cglib $ callback_0 == null) {cglib $ bind_callbacks (this); var10000 = this.cglib $ llamado Callback_0; } if (var10000! = null) {objeto var1 = var10000.intercept (this, cglib $ hashcode $ 3 $ método, cglib $ vacungs, cglib $ hashcode $ 3 $ proxy); return var1 == null? 0: ((número) var1) .intvalue (); } else {return super.hashcode (); }} objeto final cglib $ clone $ 4 () arroja clonenotsupportedException {return super.clone (); } Protected Final Object clone () lanza ClonenOtsupportedException {MethodInterceptor Var10000 = this.cglib $ llamado Callback_0; if (this.cglib $ callback_0 == null) {cglib $ bind_callbacks (this); var10000 = this.cglib $ llamado Callback_0; } return Var10000! = NULL? Var10000.intercept (this, cglib $ clone $ 4 $ método, cglib $ vacungs, cglib $ clone $ 4 $ proxy): super.clone (); } Public Static MethodProxy CGLIB $ FindMethodProxy (Signature Var0) {String var10000 = var0.ToString (); switch (var10000.hashcode ()) {case -2138148221: if (var10000.equals ("createOrder () v")) {return cglib $ createorder $ 0 $ proxy; } romper; Caso -508378822: if (var10000.equals ("clone () ljava/lang/object;")) {return cglib $ clone $ 4 $ proxy; } romper; Caso 1826985398: if (var10000.equals ("es igual (ljava/lang/object;) z")) {return cglib $ es igual a $ 1 $ proxy; } romper; Caso 1913648695: if (var10000.equals ("toString () ljava/lang/string;"))) {return cglib $ toString $ 2 $ proxy; } romper; Caso 1984935277: if (var10000.equals ("hashcode () i")) {return cglib $ hashcode $ 3 $ proxy; }} return null; } Public OrderServiceImpl $$ FormerBycglib $$ 17779AA4 () {cglib $ bind_callbacks (this); } public static void cglib $ set_thread_callbacks (devolución de llamada [] var0) {cglib $ thread_callbacks.set (var0); } public static void cglib $ set_static_callbacks (devolución de llamada [] var0) {cglib $ static_callbacks = var0; } Private static final void cglib $ bind_callbacks (Object var0) {OrderServiceImpl $$ mejorbycglib $$ 17779AA4 var1 = (OrderServiceImpl $$ FOVERBYCGLIB $$ 17779AA4) Var0; if (! var1.cglib $ bound) {var1.cglib $ bound = true; Objeto var10000 = cglib $ thread_callbacks.get (); if (var10000 == null) {var10000 = cglib $ static_callbacks; if (cglib $ static_callbacks == null) {return; }} var1.cglib $ callback_0 = (MethodInterceptor) ((Callback []) var10000) [0]; }} Public Object NewInStance (devolución de llamada [] var1) {cglib $ set_thread_callbacks (var1); OrderServiceImpl $$ Mentorbycglib $$ 17779AA4 VAR10000 = nuevo OrderServiceImpl $$ Mentorbycglib $$ 17779AA4 (); Cglib $ set_thread_callbacks ((devolución de llamada []) nulo); devolver VAR10000; } Public Object NewInStance (Callback var1) {cglib $ set_thread_callbacks (nueva devolución de llamada [] {var1}); OrderServiceImpl $$ Mentorbycglib $$ 17779AA4 VAR10000 = nuevo OrderServiceImpl $$ Mentorbycglib $$ 17779AA4 (); Cglib $ set_thread_callbacks ((devolución de llamada []) nulo); devolver VAR10000; } Public Object NewInStance (clase [] var1, objeto [] var2, devolución de llamada [] var3) {cglib $ set_thread_callbacks (var3); OrderServiceImpl $$ Mentorbycglib $$ 17779AA4 VAR10000 = nuevo OrderServiceImpl $$ Mentorbycglib $$ 17779AA4; switch (var1.length) {Case 0: Var10000. <Init> (); Cglib $ set_thread_callbacks ((devolución de llamada []) nulo); devolver VAR10000; predeterminado: tirar nueva ilegalargumentException ("constructor no encontrado"); }} public Callback getCallback (int var1) {cglib $ bind_callbacks (this); MethodInterceptor VAR10000; switch (var1) {caso 0: var10000 = this.cglib $ callback_0; romper; predeterminado: var10000 = null; } return Var10000; } public void setCallback (int var1, llamado var2) {switch (var1) {case 0: this.cglib $ callback_0 = (MethodInterceptor) var2; predeterminado:}} public Callback [] getCallbacks () {cglib $ bind_callbacks (this); devuelve nueva devolución de llamada [] {this.cglib $ llamado Callback_0}; } public void setCallbacks (Callback [] var1) {this.cglib $ callback_0 = (MethodInterceptor) var1 [0]; } static {cglib $ statichook1 (); }}En el código anterior, puede ver que la clase proxy orderserviceImpl $$ mejorbycglib $$ 17779AA4 hereda la clase de destino OrderServiceImpl e implementa la fábrica de interfaz. En la clase proxy, se generan dos métodos cglib $ createorder $ 0 y createorder:
El método CGLIB $ CreateOrder $ 0 llama directamente la supper.createOrder de la clase de destino.
El método CreateOrder primero cuenta si se implementa la devolución de llamada de la interfaz Methodinterceptor. Si existe, se llama al método de interfaz de interfaz de MethodInterceptor. Según la implementación anterior, se implementa la llamada al método de destino. Se implementa Object o1 = arg3.invokeSuper(arg0, arg2) . El Invokesuper es en realidad CGLIB$createOrder$0() de la clase proxy que se llama directamente, y finalmente se llama a la clase de destino.
Comparación de dos agentes
JDK proxy dinámico:
La clase proxy y la clase delegada implementan la misma interfaz. Implementa principalmente el Invocathandler a través de la clase Proxy y reescribe el método Invoke para realizar un proxy dinámico. El método se mejorará en el método de Invoke. Las ventajas del método: no se requiere una interfaz codificada dura y la tasa de reutilización del código es alta. Desventajas: solo la clase delegada que puede ser implementada por la interfaz
Proxy dinámico CGLIB:
La clase proxy toma la clase delegada como su clase principal y crea dos métodos para los métodos delegados no finales en ella. Uno es el mismo método que la firma del método delegado, que llamará al método delegado a través de Super en el método; El otro es el método exclusivo de la clase proxy. En el método de proxy, determinará si hay un objeto que implementa la interfaz de Interceptor del método. Si existe, se llamará al método de intercepción para representar el método delegado. Ventajas: puede mejorar el funcionamiento de la clase o interfaz en tiempo de ejecución, y la clase delegada no necesita implementar la interfaz. Desventajas: no puede representar la clase final y el método final.
Resumir
Lo anterior es todo el contenido de este artículo. Espero que el contenido de este artículo tenga cierto valor de referencia para el estudio o el trabajo de todos. Si tiene alguna pregunta, puede dejar un mensaje para comunicarse. Gracias por su apoyo a Wulin.com.