The concept of AOP
AOP: Aspect-Oriented Programming (sectional-oriented programming), Wikipedia explains it as follows: Aspect is a new modular mechanism used to describe cross-sectional concerns scattered in objects, classes or functions. Separating cross-sectional concerns from concerns is the core concept of tangent-oriented programming. Separating the focus makes the code that solves specific domain problems independent of business logic. The code of business logic does not contain calls to code for specific domain problems. The relationship between business logic and specific domain problems is encapsulated and maintained through sections, so that changes that were originally scattered throughout the application can be well managed. From the perspective of AOP, applications can be divided into cross-sectional concerns and business logic code. In actual development, these cross-sectional concerns are often directly embedded in business logic code. Face-oriented programming is to solve the problem of separating cross-sectional concerns from business logic.
Implementation method:
Spring uses JDK dynamic proxy as AOP's proxy by default. The flaw is that the target class must implement an interface, otherwise the JDK dynamic proxy cannot be used. If the class is a class rather than an interface, Spring will use CGLIB proxy by default. Regarding the difference between the two: jdk dynamic proxy is implemented through Java's reflection mechanism, the target class must implement interfaces, and cglib implements proxy for classes. Its principle is to dynamically generate a subclass for the specified target class and override the method implementation enhancement, but because inheritance is used, the final modified class cannot be proxyed.
JDK dynamic proxy
Jdk dynamic proxy dynamically generates class files of proxy classes based on the interface implemented by the target class during the program operation. The use mainly involves two classes:
InvocationHandler interface: It provides an invoke(Object obj,Method method, Object[] args) method for implementers to provide corresponding proxy logic implementation. Some special processing can be performed on the actual implementation, and the parameters are
Object obj: The target class that is proxyed
Method method: Method of the target class that needs to be executed
Object[] args: Parameters of the target method
Proxy class: Provide a method newProxyInstance (ClassLoader loader, Class[] interfaces, InvocationHandler h) to obtain dynamic proxy class
Sample code:
public interface OrderService { public void createOrder(); } public class OrderServiceImpl implements OrderService { @Override public void createOrder() { System.out.println("creating order"); }} public class OrderLogger { public void beforeCreateOrder(){ System.out.println("before create order"); } public void afterCreateOrder(){ System.out.println("after create order"); }} package com.sl.aop;import java.lang.reflect.InvocationHandler;import java.lang.reflect.Method;import java.lang.reflect.Proxy;public class ServiceProxy implements InvocationHandler { private Object targetClass; private OrderLogger orderLogger; public ServiceProxy(Object targetClass,OrderLogger orderLogger) { this.targetClass = targetClass; this.orderLogger = orderLogger; } //Get proxy public Object GetDynamicProxy() { return Proxy.newProxyInstance(targetClass.getClass().getClassLoader(), //Create proxy object through this ClassLoader targetClass.getClass().getInterfaces(), //The interface this implemented by the proxy class); //The dynamic proxy call method is the associated InvocationHandler, and finally executes the real method through the invoke method of this InvocationHandler} //Implement the corresponding proxy logic @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { this.orderLogger.beforeCreateOrder(); Object result= method.invoke(targetClass, args); this.orderLogger.afterCreateOrder(); return result; }}Test class:
package 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) new ServiceProxy(serviceImpl, logger).GetDynamicProxy(); service.createOrder(); }}Running results:
I'm actually a little confused when I reach this point. What does Proxy.newProxyInstance() return? Where is the Invoke method called? Let's take a look at the JDK source code: see what the process of DK dynamic proxy looks like:
Call Proxy.newProxyInstance()->Proxy.getProxyClass0()->WeakCache.get() according to the function inside the source code, and first locate it
WeakCache.class:
public V get(K key, P parameter) { Objects.requireNonNull(parameter); expungeStaleEntries(); Object cacheKey = CacheKey.valueOf(key, refQueue); // lazily install the 2nd level valuesMap for the particular cacheKey ConcurrentMap<Object, Supplier<V>> valuesMap = map.get(cacheKey); if (valuesMap == null) { ConcurrentMap<Object, Supplier<V>> oldValuesMap = map.putIfAbsent(cacheKey, valuesMap = new ConcurrentHashMap<>()); if (oldValuesMap != null) { valuesMap = oldValuesMap; } } // create subKey and retrieve the possible Supplier<V> stored by that // subKey from valuesMap Object subKey = Objects.requireNonNull(subKeyFactory.apply(key, parameter)); Supplier<V> supplier = valuesMap.get(subKey); Factory factory = null; while (true) { if (supplier != null) { // supplier might be a Factory or a CacheValue<V> instance V value = supplier.get(); if (value != null) { return value; } } // else no supplier in cache // or a supplier that returned null (can be a cleared CacheValue // or a Factory that wasn't successful in installing the CacheValue) // lazily construct a Factory if (factory == null) { factory = new Factory(key, parameter, subKey, valuesMap); } if (supplier == null) { supplier = valuesMap.putIfAbsent(subKey, factory); if (supplier == null) { // successfully installed Factory supplier = factory; } // else retry with winning supplier } else { if (valuesMap.replace(subKey, supplier, factory)) { // successfully replaced // cleared CacheEntry / unsuccessful Factory // with our Factory supplier = factory; } else { // retry with current supplier supplier supplier = valuesMap.get(subKey); } } } } You can see the function return value; and V value = supplier.get(); Continue to read it down and find that supper=factory is actually a Factory object, so continue to view Factory.get() method
public synchronized V get() { // serialize access // re-check Supplier<V> supplier = valuesMap.get(subKey); if (supplier != this) { // something changed while we were waiting: // might be that we were replaced by a CacheValue // or were removed because of failure -> // return null to signal WeakCache.get() to retry // the loop return null; } // else still us (supplier == this) // create new value V value = null; try { value = Objects.requireNonNull(valueFactory.apply(key, parameter)); } finally { if (value == null) { // remove us on failure valuesMap.remove(subKey, this); } } // the only path to reach here is with non-null value assert value != null; // wrap value with CacheValue (WeakReference) CacheValue<V> cacheValue = new CacheValue<>(value); // try replacing us with CacheValue (this should always succeed) if (valuesMap.replace(subKey, this, cacheValue)) { // put also in reverseMap reverseMap.put(cacheValue, Boolean.TRUE); } else { throw new AssertionError("Should not reach here"); } // successfully replaced us with new CacheValue -> return the value // wrapped by it return value; } Return value; then directly view the assignment statement: value = Objects.requireNonNull(valueFactory.apply(key, parameter));
What the hell is valueFactory?
public WeakCache(BiFunction<K, P, ?> subKeyFactory, BiFunction<K, P, V> valueFactory) { this.subKeyFactory = Objects.requireNonNull(subKeyFactory); this.valueFactory = Objects.requireNonNull(valueFactory); }private static final WeakCache<ClassLoader, Class<?>[], Class<?>> proxyClassCache = new WeakCache<>(new KeyFactory(), new ProxyClassFactory()); You can know that valueFactory is a ProxyClassFactory type object, and directly view ProxyClassFactory. Apply() method
public Class<?> apply(ClassLoader loader, Class<?>[] interfaces) { Map<Class<?>, Boolean> interfaceSet = new IdentityHashMap<>(interfaces.length); for (Class<?> intf : interfaces) { /* * Verify that the class loader resolves the name of this * interface to the same Class object. */ Class<?> interfaceClass = null; try { interfaceClass = Class.forName(intf.getName(), false, loader); } catch (ClassNotFoundException e) { } if (interfaceClass != intf) { throw new IllegalArgumentException( intf + " is not visible from class loader"); } /* * Verify that the Class object actually represents an * interface. */ if (!interfaceClass.isInterface()) { throw new IllegalArgumentException( interfaceClass.getName() + " is not an interface"); } /* * Verify that this interface is not a duplicate. */ if (interfaceSet.put(interfaceClass, Boolean.TRUE) != null) { throw new IllegalArgumentException( "repeated interface: " + interfaceClass.getName()); } } String proxyPkg = null; // package to define proxy class in int accessFlags = Modifier.PUBLIC | Modifier.FINAL; /* * Record the package of a non-public proxy interface so that the * proxy class will be defined in the same package. Verify that * all non-public proxy interfaces are in the same package. */ for (Class<?> intf : interfaces) { int flags = intf.getModifiers(); if (!Modifier.isPublic(flags)) { accessFlags = Modifier.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)) { throw new IllegalArgumentException( "non-public interfaces from different packages"); } } } } if (proxyPkg == null) { // if no non-public proxy interfaces, use com.sun.proxy package proxyPkg = ReflectUtil.PROXY_PACKAGE + "."; } /* * Choose a name for the proxy class to generate. */ long num = nextUniqueNumber.getAndIncrement(); String proxyName = proxyPkg + proxyClassNamePrefix + num; /* * Generate the specified proxy class. */ byte[] proxyClassFile = ProxyGenerator.generateProxyClass( proxyName, interfaces, accessFlags); try { return defineClass0(loader, proxyName, proxyClassFile, 0, proxyClassFile.length); } catch (ClassFormatError e) { /* * A ClassFormatError here means that (barring bugs in the * proxy class generation code) there was some other * invalid aspect of the arguments supplied to the proxy * class creation (such as virtual machine limitations * exceeded). */ throw new IllegalArgumentException(e.toString()); } }}Directly draw the key points:
byte[] proxyClassFile = ProxyGenerator.generateProxyClass( proxyName, interfaces, accessFlags); return defineClass0(loader, proxyName, proxyClassFile, 0, proxyClassFile.length);
Calling ProxyGenerator.generateProxyClass finally dynamically generates a proxy class, but it seems that nowhere is found to be called invoke; refer to the article CSDN: //www.VeVB.COM/article/118935.htm, try to output the dynamically generated binary bytecode locally and decompile it to see what it is. The test code is as follows:
public class AopTest { @Test public void Testdynamicproxy() { OrderServiceImpl serviceImpl = new OrderServiceImpl(); OrderLogger logger = new OrderLogger(); OrderService service = (OrderService) new ServiceProxy(serviceImpl, logger).GetDynamicProxy(); service.createOrder(); //Output dynamic proxy class 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((new File("hello")).getAbsolutePath()); out.write(data); } catch (FileNotFoundException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); } finally { if(null!=out) try { out.close(); } catch (IOException e) { e.printStackTrace(); } } } } } }Use the Java Decompiler tool to decompile this binary class file:
Specific dynamic proxy class 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 extends Proxy implements OrderService{ private static Method m1; private static Method m2; private static Method m3; private static Method m0; public ProxyObject(InvocationHandler paramInvocationHandler) { super(paramInvocationHandler); } public final boolean equals(Object paramObject) { try { return ((Boolean)this.h.invoke(this, m1, new Object[] { paramObject })).booleanValue(); } catch (Error|RuntimeException localError) { throw localError; } catch (Throwable localThrowable) { throw new UndeclaredThrowableException(localThrowable); } } public final String toString() { try { return (String)this.h.invoke(this, m2, null); } catch (Error|RuntimeException localError) { throw localError; } catch (Throwable localThrowable) { throw new UndeclaredThrowableException(localThrowable); } } public final void createOrder() { try { this.h.invoke(this, m3, null); return; } catch (Error|RuntimeException localError) { throw localError; } catch (Throwable localThrowable) { throw new UndeclaredThrowableException(localThrowable); } } public final int hashCode() { try { return ((Integer)this.h.invoke(this, m0, null)).intValue(); } catch (Error|RuntimeException localError) { throw localError; } catch (Throwable localThrowable) { throw new UndeclaredThrowableException(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]); return; } catch (NoSuchMethodException localNoSuchMethodException) { throw new NoSuchMethodError(localNoSuchMethodException.getMessage()); } catch (ClassNotFoundException localClassNotFoundException) { throw new NoClassDefFoundError(localClassNotFoundException.getMessage()); } }Finally saw the part about invoke:
public final void createOrder() { try { this.h.invoke(this, m3, null); return; } catch (Error|RuntimeException localError) { throw localError; } catch (Throwable localThrowable) { throw new UndeclaredThrowableException(localThrowable); } }In fact, the dynamic proxy class inherits from Proxy and implements the interface inherited by the target class. The invoke method is called in the createOrder method, which implements the implantation of sectional logic. Here we also answer a question, why the target class of the JDK dynamic proxy must implement the interface, because the proxy class is actually aimed at the interface proxy, not the class. The dynamic proxy class inherits itself from Proxy, and Java does not allow multiple inheritance. The dynamic proxy class and the target class actually implement the interfaces respectively. The proxy class realizes the call to the target class method through InvocationHandler.invoke.
CGLIB Dynamic Proxy
The CGLIB proxy uses a bytecode processing framework ASM to convert bytecode and generate new classes, and uses method intercepting techniques in subclasses to intercept all parent class methods to implement cross-cutting logic, which is more efficient than the JDK dynamic proxy using reflection technology. However, since the principle of CGLIB is to dynamically generate subclass proxy classes for the target class, it cannot be proxyed for methods declared as final. Its use mainly involves two categories:
MethodInterceptor interface: This interface provides a method intercept(Object arg0, Method arg1, Object[] arg2, MethodProxy arg3) mainly used to intercept the call of target class methods.
Object arg0,: the target class that is being proxied
Method arg1, delegate method
Object[] arg2, method parameters
MethodProxy arg3: MethodProxy object of proxy method
Enhancer class: used to create proxy class
Example:
Implement the MethodInterceptor interface. When the proxy class calls a method, CGLIB will call back the MethodInterceptor interface intercept method, thereby weaving the surface logic.
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;public class CglibServiceProxy implements MethodInterceptor { private Object targetClass; private OrderLogger orderLogger; public CglibServiceProxy(Object targetClass,OrderLogger orderLogger) { this.targetClass = targetClass; this.orderLogger = orderLogger; } /** * Create a proxy object* */ public Object getInstance() { Enhancer enhancer = new Enhancer(); //Set the target class (class that needs to be proxyed) enhancer.setSuperclass(this.targetClass.getClass()); //Callback method enhancer.setCallback(this); //Create proxy object return enhance.create(); } /** * Intercept all target class methods* */ @Override public Object intercept(Object arg0, Method arg1, Object[] arg2, MethodProxy arg3) throws Throwable { orderLogger.beforeCreateOrder(); Object o1 = arg3.invokeSuper(arg0, arg2); orderLogger.afterCreateOrder(); return o1; }}Test method:
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); //Create a proxy class by generating subclasses OrderServiceImpl proxyImp = (OrderServiceImpl)proxy.getInstance(); proxyImp.createOrder(); }result:
System.setProperty(DebuggingClassWriter.DEBUG_LOCATION_PROPERTY, "D://class"); output cglib dynamic proxy class to the specified directory, decompile and check the true face of the proxy class:
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;import org.springframework.cglib.proxy.Factory;import org.springframework.cglib.proxy.MethodInterceptor;import org.springframework.cglib.proxy.MethodProxy;public class OrderServiceImpl$$EnhancerByCGLIB$$17779aa4 extends OrderServiceImpl implements Factory { private boolean CGLIB$BOUND; public static Object CGLIB$FACTORY_DATA; private static final ThreadLocal CGLIB$THREAD_CALLBACKS; private static final Callback[] CGLIB$STATIC_CALLBACKS; private MethodInterceptor CGLIB$CALLBACK_0; private static Object CGLIB$CALLBACK_FILTER; private static final Method CGLIB$createOrder$0$Method; private static final Method Proxy CGLIB$createOrder$0$Proxy; private static final Object[] CGLIB$emptyArgs; private static final Method CGLIB$equals$1$Method; private static final MethodProxy CGLIB$equals$1$Proxy; private static final Method CGLIB$toString$2$Method; private static final MethodProxy CGLIB$toString$2$Proxy; private static final Method CGLIB$hashCode$3$Method; private static final MethodProxy CGLIB$hashCode$3$Proxy; private static final MethodCGLIB$clone$4$Method; private static final MethodProxy CGLIB$clone$4$Proxy; static void CGLIB$STATICHOOK1() { CGLIB$THREAD_CALLBACKS = new ThreadLocal(); CGLIB$emptyArgs = new Object[0]; Class var0 = Class.forName("com.sl.aop.OrderServiceImpl$$EnhancerByCGLIB$$17779aa4"); Class var1; Method[] var10000 = ReflectUtils.findMethods(new String[]{"equals", "(Ljava/lang/Object;)Z", "toString", "()Ljava/lang/String;", "hashCode", "()I", "clone", "()Ljava/lang/Object;"}, (var1 = Class.forName("java.lang.Object")).getDeclaredMethods()); CGLIB$equals$1$Method = var10000[0]; CGLIB$equals$1$Proxy = MethodProxy.create(var1, var0, "(Ljava/lang/Object;)Z", "equals", "CGLIB$equals$1"); CGLIB$toString$2$Method = var10000[1]; CGLIB$toString$2$Proxy = MethodProxy.create(var1, var0, "()Ljava/lang/String;", "toString", "CGLIB$toString$2"); CGLIB$hashCode$3$Method = var10000[2]; CGLIB$hashCode$3$Proxy = MethodProxy.create(var1, var0, "()I", "hashCode", "CGLIB$hashCode$3"); CGLIB$clone$4$Method = var10000[3]; CGLIB$clone$4$Proxy = MethodProxy.create(var1, var0, "()Ljava/lang/Object;", "clone", "CGLIB$clone$4"); CGLIB$createOrder$0$Method = ReflectUtils.findMethods(new String[]{"createOrder", "()V"}, (var1 = Class.forName("com.sl.aop.OrderServiceImpl")).getDeclaredMethods())[0]; CGLIB$createOrder$0$Proxy = MethodProxy.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$Method, CGLIB$emptyArgs, CGLIB$createOrder$0$Proxy); } else { super.createOrder(); } } final boolean CGLIB$equals$1(Object var1) { return super.equals(var1); } public final boolean equals(Object 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) { Object var2 = var10000.intercept(this, CGLIB$equals$1$Method, new Object[]{var1}, CGLIB$equals$1$Proxy); return var2 == null?false:((Boolean)var2).booleanValue(); } else { return super.equals(var1); } } final String 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$Method, CGLIB$emptyArgs, CGLIB$toString$2$Proxy):super.toString(); } final int CGLIB$hashCode$3() { return super.hashCode(); } public final int hashCode() { MethodInterceptor var10000 = this.CGLIB$CALLBACK_0; if(this.CGLIB$CALLBACK_0 == null) { CGLIB$BIND_CALLBACKS(this); var10000 = this.CGLIB$CALLBACK_0; } if(var10000 != null) { Object var1 = var10000.intercept(this, CGLIB$hashCode$3$Method, CGLIB$emptyArgs, CGLIB$hashCode$3$Proxy); return var1 == null?0:((Number)var1).intValue(); } else { return super.hashCode(); } } final Object CGLIB$clone$4() throws CloneNotSupportedException { return super.clone(); } protected final Object clone() throws 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$Method, CGLIB$emptyArgs, 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; } break; case -508378822: if(var10000.equals("clone()Ljava/lang/Object;")) { return CGLIB$clone$4$Proxy; } break; case 1826985398: if(var10000.equals("equals(Ljava/lang/Object;)Z")) { return CGLIB$equals$1$Proxy; } break; case 1913648695: if(var10000.equals("toString()Ljava/lang/String;"))) { return CGLIB$toString$2$Proxy; } break; 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(Object var0) { OrderServiceImpl$$EnhancerByCGLIB$$17779aa4 var1 = (OrderServiceImpl$$EnhancerByCGLIB$$17779aa4)var0; if(!var1.CGLIB$BOUND) { var1.CGLIB$BOUND = true; Object 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(Callback[] var1) { CGLIB$SET_THREAD_CALLBACKS(var1); OrderServiceImpl$$EnhancerByCGLIB$$17779aa4 var10000 = new OrderServiceImpl$$EnhancerByCGLIB$$17779aa4(); CGLIB$SET_THREAD_CALLBACKS((Callback[])null); return var10000; } public Object newInstance(Callback var1) { CGLIB$SET_THREAD_CALLBACKS(new Callback[]{var1}); OrderServiceImpl$$EnhancerByCGLIB$$17779aa4 var10000 = new OrderServiceImpl$$EnhancerByCGLIB$$17779aa4(); CGLIB$SET_THREAD_CALLBACKS((Callback[])null); return var10000; } public Object newInstance(Class[] var1, Object[] var2, Callback[] var3) { CGLIB$SET_THREAD_CALLBACKS(var3); OrderServiceImpl$$EnhancerByCGLIB$$17779aa4 var10000 = new OrderServiceImpl$$EnhancerByCGLIB$$17779aa4; switch(var1.length) { case 0: var10000.<init>(); CGLIB$SET_THREAD_CALLBACKS((Callback[])null); return var10000; default: throw new IllegalArgumentException("Constructor not found"); } } public Callback getCallback(int var1) { CGLIB$BIND_CALLBACKS(this); MethodInterceptor var10000; switch(var1) { case 0: var10000 = this.CGLIB$CALLBACK_0; break; default: var10000 = null; } return var10000; } public void setCallback(int var1, Callback var2) { switch(var1) { case 0: this.CGLIB$CALLBACK_0 = (MethodInterceptor)var2; default: } } public Callback[] getCallbacks() { CGLIB$BIND_CALLBACKS(this); return new Callback[]{this.CGLIB$CALLBACK_0}; } public void setCallbacks(Callback[] var1) { this.CGLIB$CALLBACK_0 = (MethodInterceptor)var1[0]; } static { CGLIB$STATICHOOK1(); }}In the above code, you can see that the proxy class OrderServiceImpl$$EnhancerByCGLIB$$17779aa4 inherits the target class OrderServiceImpl and implements the interface Factory. In the proxy class, two methods CGLIB$createOrder$0 and createOrder are generated:
The CGLIB$createOrder$0 method directly calls the target class's supper.createOrder
The createOrder method first counts whether the callback of the MethodInterceptor interface is implemented. If it exists, the MethodInterceptor interface intercept method is called. According to the previous implementation, the call to the target method is implemented. Object o1 = arg3.invokeSuper(arg0, arg2) is implemented. The invokeSuper is actually CGLIB$createOrder$0() method of the proxy class that is directly called, and the target class createOrder is finally called.
Comparison of two agents
JDK dynamic proxy:
The proxy class and the delegate class implement the same interface. It mainly implements the InvocationHandler through the proxy class and rewrites the invoke method to perform dynamic proxying. The method will be enhanced in the invoke method. The advantages of the method: no hard-coded interface is required, and the code reuse rate is high. Disadvantages: Only the delegate class that can be implemented by the interface
CGLIB Dynamic Proxy:
The proxy class takes the delegate class as its parent class and creates two methods for the non-final delegate methods in it. One is the same method as the delegate method signature, which will call the delegate method through super in the method; the other is the method unique to the proxy class. In the proxy method, it will determine whether there is an object that implements the MethodInterceptor interface. If it exists, the intercept method will be called to proxy the delegate method. Advantages: it can enhance the operation of the class or interface at runtime, and the delegate class does not need to implement the interface. Disadvantages: it cannot proxy the final class and final method.
Summarize
The above is the entire content of this article. I hope that the content of this article has certain reference value for everyone's study or work. If you have any questions, you can leave a message to communicate. Thank you for your support to Wulin.com.