From: original text
Characteristics of agency
1) Executor, principal
2) For the agent, it must be done or there is no time to do it. Find an agent
3) Need to obtain the personal data of the person being represented
Examples in life: 1. Train ticket scalpers; 2. Rental agents
one JDK And CGLIB dynamic agent principle
1. JDK dynamic agent
Use the interceptor (the interceptor must implement InvocationHanlder) and the reflection mechanism to generate an anonymous class that implements the proxy interface,
Call InvokeHandler before processing the specific method.
2. CGLiB dynamic proxy
Using ASM open source package, load the class file of proxy object class, and generate subclasses by modifying its bytecode.
3. When to use JDK or CGLiB?
1) If the target object implements the interface, the dynamic proxy of JDK will be used to implement AOP by default.
2) If the target object implements an interface, you can force the use of CGLIB to implement AOP.
3) If the target object does not implement the interface, the CGLIB library must be used, and Spring will automatically convert between JDK dynamic proxy and CGLIB.
4. How to force the use of CGLIB to implement AOP?
1) Add CGLIB libraries (aspectjrt-xxx.jar, aspectjweaver-xxx.jar, cglib-nodep-xxx.jar)
2) Add < AOP: AspectJ AutoProxy proxy target class = "true" / > to the Spring configuration file
5. What is the difference between JDK dynamic proxy and CGLIB bytecode generation?
1) JDK dynamic proxy can only generate proxy for classes that implement interfaces, not for classes.
2) CGLIB implements a proxy for a class. It mainly generates a subclass of a specified class and overrides the methods in it,
And override the method implementation enhancement, but because inheritance is adopted, it is better not to declare this class or method as final,
For final classes or methods, you cannot inherit.
6. CGlib is faster than JDK?
1) CGLib is used to implement dynamic proxy. The bottom layer of CGLib adopts ASM bytecode generation framework and bytecode technology to generate proxy classes, which is more efficient than Java reflection before jdk6. The only thing to note is that CGLib cannot proxy a method declared as final, because the principle of CGLib is to dynamically generate subclasses of the proxy class.
2) After jdk6, jdk7 and jdk8 gradually optimize the JDK dynamic agent, the JDK agent efficiency is higher than the CGLIB agent efficiency when the number of calls is small. Only when a large number of calls are made, the jdk6 and jdk7 are a little lower than the CGLIB agent efficiency, but when jdk8, the JDK agent efficiency is higher than the CGLIB agent. In short, every JDK Version upgrade , jdk agent efficiency has been improved, and CGLIB agent messages really can't keep up with the pace.
7. How does Spring choose JDK or CGLiB?
1) When the Bean implements the interface, Spring will use the dynamic proxy of JDK.
2) When the Bean does not implement the interface, Spring uses CGlib to implement it.
3) You can force the use of CGlib (add < AOP: AspectJ AutoProxy proxy target class = "true" / > to the spring configuration).
II. Code example
Interface:
package com.lanhuigu.spring.proxy.compare; /** * User management interface (common interface between real topic and proxy topic, so that proxy topic proxy can be used wherever real topic can be used.) *-- Proxy interface definition */ public interface IUserManager { void addUser(String id, String password); }
Implementation class:
package com.lanhuigu.spring.proxy.compare; /** * User management interface implementation (implementation class of proxy) */ public class UserManagerImpl implements IUserManager { @Override public void addUser(String id, String password) { System.out.println("======Called UserManagerImpl.addUser()method======"); } }
JDK agent implementation:
package com.lanhuigu.spring.proxy.compare; import java.lang.reflect.InvocationHandler;import java.lang.reflect.Method;import java.lang.reflect.Proxy; /** * JDK Dynamic proxy class */ public class JDKProxy implements InvocationHandler { /** Target object requiring proxy */ private Object targetObject; /** * Pass in the target object for proxy */ public Object newProxy(Object targetObject) { this.targetObject = targetObject; //Return proxy object return Proxy.newProxyInstance(targetObject.getClass().getClassLoader(),targetObject.getClass().getInterfaces(), this); } /** * invoke method */ @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { // Generally, we perform logic processing functions. For example, this place simulates checking permissions checkPopedom(); // Set the return value of the method Object ret = null; // Call the invoke method, and ret stores the return value of the method ret = method.invoke(targetObject, args); return ret; } /** * Example of simulated check permission */ private void checkPopedom() { System.out.println("======Check permissions checkPopedom()======"); } }
CGLIB proxy implementation:
package com.lanhuigu.spring.proxy.compare; import net.sf.cglib.proxy.Enhancer; import net.sf.cglib.proxy.MethodInterceptor;import net.sf.cglib.proxy.MethodProxy; import java.lang.reflect.Method; /** * CGLibProxy Dynamic proxy class */ public class CGLibProxy implements MethodInterceptor { /** CGLib Target object requiring proxy */ private Object targetObject; public Object createProxyObject(Object obj) { this.targetObject = obj; Enhancer enhancer = new Enhancer(); //Who set the parent class to? //This step is to tell cglib which class the generated subclass needs to inherit enhancer.setSuperclass(obj.getClass()); enhancer.setCallback(this); Object proxyObj = enhancer.create(); // Return proxy object //Step 1: generate source code //Step 2: compile it into a class file //Step 3: load it into the JVM and return the proxy object return proxyObj; } @Override public Object intercept(Object proxy, Method method, Object[] args,MethodProxy methodProxy) throws Throwable { Object obj = null; // Filtering method if ("addUser".equals(method.getName())) { // Check permissions checkPopedom(); } obj = method.invoke(targetObject, args); //The reference of this obj is given to us new by CGLib //The object after cglib new is generated is a subclass of the proxy object (inheriting the class we wrote ourselves) //OOP, before the new subclass, actually calls our super() method by default, //When new subclasses, we must first new out the parent class, which is equivalent to indirectly holding the reference of our parent class //The subclass overrides all the methods of the parent class //We can indirectly manipulate the properties of the parent class by changing some properties of the child class object //proxy.invokeSuper(obj, args); return obj; } private void checkPopedom() { System.out.println("======Check permissions checkPopedom()======"); } }
Client test class:
package com.lanhuigu.spring.proxy.compare; /** * Proxy mode [[client -- proxy object -- target object]] */ public class Client { public static void main(String[] args) { System.out.println("**********************CGLibProxy**********************"); CGLibProxy cgLibProxy = new CGLibProxy(); IUserManager userManager = (IUserManager) cgLibProxy.createProxyObject(new UserManagerImpl()); userManager.addUser("lanhuigu", "123456"); System.out.println("**********************JDKProxy**********************"); JDKProxy jdkPrpxy = new JDKProxy(); IUserManager userManagerJDK = (IUserManager) jdkPrpxy.newProxy(new UserManagerImpl()); userManagerJDK.addUser("lanhuigu", "123456"); } }
Program running results:
III. summary of JDK and CGLIB dynamic agents
The JDK agent does not need the support of a third-party library. It can be used only in the JDK environment. The use conditions are as follows:
1) Implement InvocationHandler
2) Use proxy Newproxyinstance generates a proxy object
3) The proxy object must implement the interface
CGLib must rely on CGLib's class library, but it needs classes to implement any interface proxy. It generates a subclass from the specified class and overrides the methods in it. It is an inherited proxy, but it is recommended to use JDK in the environment of interface programming;