[Java in-depth study] 6. Detailed explanation of CGLib dynamic proxy mechanism

First, let's talk about dynamic proxy in JDK:

Dynamic proxy in JDK is implemented by reflective class Proxy and InvocationHandler callback interface

However, the dynamic proxy class in JDK must implement an interface, that is to say, it can only proxy the methods defined in the interface. This has some limitations in practical programming, and the efficiency of using reflection is not very high.

2. Using CGLib to implement:

Using CGLib to implement dynamic proxy is completely free from the restriction that proxy classes must implement interfaces. Moreover, the bottom layer of CGLib uses ASM bytecode generation framework, and using bytecode technology to generate proxy classes is more efficient than using Java reflection. The only thing to note is that CGLib cannot proxy methods declared final because CGLib principle is to dynamically generate subclasses of proxy classes.

Next, we will introduce the implementation of dynamic proxy using CGLib through an example.

1. Agent class:

First, define a class that does not implement any interfaces and contains two methods.

  1. public class ConcreteClassNoInterface {  
  2.     public String getConcreteMethodA(String str){  
  3.         System.out.println("ConcreteMethod A ... "+str);  
  4.         return str;  
  5.     }  
  6.     public int getConcreteMethodB(int n){  
  7.         System.out.println("ConcreteMethod B ... "+n);  
  8.         return n+10;  
  9.     }  
  10. }  

2. Interceptor:

Define an interceptor. When calling the target method, CGLib calls back the method Interceptor interface method interception to implement your own proxy logic, similar to the Invocation Handler interface in JDK.

  1. public class ConcreteClassInterceptor implements MethodInterceptor{  
  2.     public Object intercept(Object obj, Method method, Object[] arg, MethodProxy proxy) throws Throwable {  
  3.         System.out.println("Before:"+method);    
  4.         Object object=proxy.invokeSuper(obj, arg);  
  5.         System.out.println("After:"+method);   
  6.         return object;  
  7.     }  
  8. }  

Parameters: Object is a proxy class instance dynamically generated by CGLib, Method is a proxy method reference called by entity class, Object [] is a list of parameter values, and MethodProxy is a proxy reference of method for generated proxy class.

Return: The value returned from the method call of the proxy instance.

Among them, proxy.invokeSuper(obj,arg):

Call the parent method of the proxy method on the proxy class instance (that is, the corresponding method in the entity class ConcreteClassNoInterface)

In this example, only one sentence is printed before and after the proxy class method is called, of course, other complex logic can be used in actual programming.

3. Generate dynamic proxy classes:

  1. Enhancer enhancer=new Enhancer();  
  2. enhancer.setSuperclass(ConcreteClassNoInterface.class);  
  3. enhancer.setCallback(new ConcreteClassInterceptor());  
  4. ConcreteClassNoInterface ccni=(ConcreteClassNoInterface)enhancer.create();  

Here the Enhancer class is a bytecode enhancer in CGLib. It can easily extend the classes you want to handle, and you will see it often in the future.

First, the proxy class ConcreteClassNoInterface is set as the parent class, then the interceptor ConcreteClassInterceptor is set, and finally enhancer.create() is executed to dynamically generate a proxy class, which is forced from Object to the parent type ConcreteClassNoInterface.

Finally, the method is invoked on the proxy class:

  1. ccni.getConcreteMethodA("shensy");  
  2. ccni.getConcreteMethodB(0);  

View console output:

  1. Before :public java.lang.String generic.cglib.proxy.ConcreteClassNoInterface.getConcreteMethodA(java.lang.String)  
  2. ConcreteMethod A ... shensy  
  3. After :public java.lang.String generic.cglib.proxy.ConcreteClassNoInterface.getConcreteMethodA(java.lang.String)  
  4. Before :public int generic.cglib.proxy.ConcreteClassNoInterface.getConcreteMethodB(int)  
  5. ConcreteMethod B ... 0  
  6. After :public int generic.cglib.proxy.ConcreteClassNoInterface.getConcreteMethodB(int)  

As you can see, the interceptor performs print operations before and after calling the proxy class method.

From: http://shensy.iteye.com/blog/1873155

Keywords: Java JDK Programming

Added by ram4nd on Fri, 12 Jul 2019 21:53:45 +0300