In-depth analysis of dynamic proxy, in-depth analysis of dynamic
Dynamic proxy refers to the dynamic generation of proxy classes at runtime. The byte code of the proxy class will be generated and loaded into the current ClassLoader at runtime.
There are many ways to generate a dynamic proxy class, such as the dynamic proxy, CGLIB, Javassist, or ASM library that comes with JDK.
JDK dynamic proxy is easy to use and built-in in JDK. Therefore, third-party Jar packages are not required, but the functions are relatively weak. CGLIB and ipvsist are both advanced bytecode generation libraries. The overall performance is better than the built-in dynamic proxy of JDK, and the functions are very powerful. ASM is a low-level bytecode generation tool. It is almost used for Javabytecode programming. It has high requirements on developers and is also the best dynamic proxy birthdate tool. However, the use of ASM is too cumbersome, and the performance has not been improved by an order of magnitude. Compared with advanced bytecode generation tools such as CGLIB, the maintainability of the ASM Program is also poor.
JDK implementation
1. Steps
1) Create your own call processor through the InvocationHandler Interface
2) create a dynamic Proxy class by specifying a ClassLoader object and a group of interfaces for the Proxy class
3) obtain the constructor of the dynamic proxy class through the reflection mechanism. The unique parameter type is the type of the called processor interface.
4) create a dynamic proxy instance through the constructor. During the constructor, the processor object is called as a parameter and passed in.
2. Create a proxy
// InvocationHandlerImpl implements the InvocationHandler interface and can distribute and forward method calls from the proxy class to the delegate class. // It usually contains references pointing to the delegate class instance, call InvocationHandler handler = new InvocaitonHandlerImpl (...) to truly execute the method forwarded by the dispatch (..); // use Proxy to dynamically create the Proxy Class object Class clazz = Proxy for a group of interfaces including Interface interfaces. getProxyClass (classLoader, new Class [] {Interface. class ,...}); // obtain the Constructor constructor = clazz from the generated class object through reflection. getConstructor (new Class [] {InvocationHandler. class}); // create an object through the constructor Create a dynamic Proxy instance Interface Proxy = (Interface) constructor. newInstance (new Object [] {handler}); // The static newProxyInstance method of the Proxy class encapsulates the last three steps of the preceding steps, simplifying the process of obtaining dynamic Proxy objects. // InvocationHandlerImpl implements the InvocaitonHandler interface, and can implement the dispatch and forwarding of method calls from the proxy class to the delegate class. InvocaitonHandler handler = new InvocationHandlerImpl (..); // directly create a dynamic Proxy instance Interface proxy = (Interface) Proxy through Proxy. newProxyInstance (classLoader, new Class [] {Interface. class}, handler );
3. Code
/*** Interface * @ author Emily **/public interface IDBQuery {String request ();}/*** real implementation class, specific target object * @ author Emily **/public class DBQuery implements IDBQuery {public DBQuery () {try {Thread. sleep (1000); // may contain time-consuming operations such as database connection} catch (InterruptedException e) {e. printStackTrace () ;}@ Overridepublic String request () {return "request string ";}} /*** JDK dynamic proxy implementation class * @ author Emily **/public class JdkDbQueryHandler implements InvocationHandler {IDBQuery real = null; // topic interface/*** generate Handler */@ Overridepublic Object invoke (Object proxy, Method method, Object [] args) throws Throwable {if (real = null) real = new DBQuery (); // if this is the first call, the real object return real is generated. request (); // complete the actual operation with the actual topic}/*** use Handler to generate a dynamic proxy object * @ return */public static IDBQuery createJdkProxy () {// return an Instance Object of the proxy class based on the specified class loader, interface, and interceptor. // ClassLoader loader: specify the Class loader of the proxy object // Class [] Interfaces: Specify the interface of the event for the proxy object // InvocationHandler h: Specify the InvocationHandler object IDBQuery jdkProxy = (IDBQuery) proxy. newProxyInstance (ClassLoader. getSystemClassLoader (), new Class [] {IDBQuery. class}, new JdkDbQueryHandler (); return jdkProxy ;}}
CGLIB implementation
Package com. ltt. dynamic; import java. lang. reflect. method; import net. sf. cglib. proxy. enhancer; import net. sf. cglib. proxy. methodInterceptor; import net. sf. cglib. proxy. methodProxy;/*** CGLIB dynamic proxy * @ author Emily **/public class CglibDbQueryInterceptor implements MethodInterceptor {IDBQuery real = null; /*** cut-in class for processing proxy logic */@ Overridepublic Object intercept (Object arg0, Method arg1, Object [] arg2, MethodProxy arg3) throws Throwable {if (real = null) {// internal logic of the proxy class real = new DBQuery (); return real. request ();} return null;}/*** generate dynamic proxy * @ return */public static IDBQuery createCglibProxy () {Enhancer enhancer = new Enhancer (); // specify the incept and define the logic of the proxy class enhancer. setCallback (new CglibDbQueryInterceptor (); // specify the implemented interface enhancer. setInterfaces (new Class [] {IDBQuery. class}); IDBQuery cglibProxy = (IDBQuery) enhancer. create (); return cglibProxy ;}}
Javassist implementation
One is to create with a proxy factory, and the other is to create with dynamic code. When using the agent factory to create a factory, the method is similar to CGLIB. You also need to implement a Handler used for Agent logic processing, such as create‑sistdynproxy (). You can use dynamic code to create and generate bytecode, this method can be very flexible, or even generate business logic at runtime, such as the create‑sistbytecodedynamicproxy () method.
/*** Javassist dynamic proxy * @ author Emily **/public class export sistdyndbqueryhandler implements MethodHandler {IDBQuery real = null;/** (non-Javadoc) implement Handler * @ see javassist for proxy logic processing. util. proxy. methodHandler # invoke (java. lang. object, java. lang. reflect. method, java. lang. reflect. method, java. lang. object []) * // @ Overridepublic Object invoke (Object arg0, Method arg1, Method arg2, Object [] arg3) throws Throwable {if (real = null) real = new DBQuery (); return real. request ();}/*** create a dynamic proxy * @ return * @ throws Exception */public static IDBQuery create‑sistdynproxy () throws Exception {ProxyFactory proxyFactory = new ProxyFactory (); proxyFactory. setInterfaces (new Class [] {IDBQuery. class}); // specifies the interface Class proxyClass = proxyFactory. createClass (); IDBQuery export sistproxy = (IDBQuery) proxyClass. newInstance (); // set the Handler processor (ProxyObject) using sistproxy ). setHandler (new JavassistDynDbQueryHandler (); return javassistProxy;}/*** generate business logic during runtime * @ return * @ throws Exception */public static IDBQuery create1_sistbytecodedynamicproxy () throws Exception {ClassPool mPool = new ClassPool (true); // defines the class name CtClass mCtc = mPool. makeClass (IDBQuery. class. getName () + "JavaassistBytecodeProxy"); // you need to implement the mCtc interface. addInterface (mPool. get (IDBQuery. class. getName (); // Add the constructor mCtc. addConstructor (CtNewConstructor. defaultConstructor (mCtc); // Add the field information of the class and use the dynamic Java code mCtc. addField (CtField. make ("public" + IDBQuery. class. getName () + "real;", mCtc); String dbQueryname = DBQuery. class. getName (); // Add method. Here dynamic Java code is used to specify the internal logic mCtc. addMethod (CtNewMethod. make ("public String request () {if (real = null) real = new" + dbQueryname + "(); return real. request ();} ", mCtc); // based on the preceding information, generate a dynamic Class pc = mCtc. toClass (); // generate an instance of the dynamic class IDBQuery bytecodeProxy = (IDBQuery) pc. newInstance (); return bytecodeProxy ;}}
Three dynamic proxies: JDK dynamic proxies are faster than CGLIB dynamic proxies, but function calling performance is far inferior to CGLIB and Javassist. Therefore, CGLIB and ipvsist have better overall performance than JDK dynamic proxy.
Dynamic proxy VS static proxy
Static proxy
1) An interface of a proxy object serves only one type of object. If there are many proxy methods, proxy is required for each method, static proxies cannot be competent when the program size is relatively large.
2) if a method is added to the interface, all the proxy classes also need to implement this method except all the implementation classes. Added the complexity of code maintenance.
Dynamic proxy
1) the source code of the dynamic proxy class is dynamically generated by JVM according to reflection and other mechanisms during the program running, so there is no bytecode file of the proxy class. The relationship between the proxy class and the delegate class is determined when the program is running.
2) compared with the static proxy, the biggest advantage is that all methods declared in the interface are transferred to the calling processor for processing in a centralized method. In this way, when there are a large number of interface methods, we can flexibly process them without the need to transfer each method like a static proxy.
3) Dynamic proxy can greatly reduce the number of lines of code and improve system flexibility.