Java dynamic proxy (JDK dynamic proxy and cglib)

Keywords: Java Back-end Dynamic Proxy

JDK dynamic agent

The dynamic proxy of JDK only allows proxy interfaces

Important classes and interfaces Proxy and InvocationHandler
The proxy.newproxyinstance (classloader, loader, class <? > [] interfaces, invocationhandler h) method creates a proxy object for the target object
After obtaining the proxy object of the target object, the method of executing the target object is actually implemented by calling the invoke method of the proxy object
We can add additional general logic to the invoke method to enhance the target object

/**
 * @Description Proxy object
 */
public class ProxyHandler implements InvocationHandler{
    private Object target;

    public Object getProxyHandler(Object target){
        this.target = target;
        Object o = Proxy.newProxyInstance(target.getClass().getClassLoader(), target.getClass().getInterfaces(), this);
        return o;
    }

    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        System.out.println("before");
        Object invoke = method.invoke(target, args);
        System.out.println("After");
        return invoke;
    }
}

After obtaining the proxy object, call the proxy object's method like calling the target object. Intuitively, it is no different from ordinary calling, but in fact, it calls the invoke method of the proxy object. There are many things that can be done in the invoke method. You can enhance or even rewrite some methods and process the specified method through method.getName()

public class ProxyHandlerTest extends TestInit {
    @Autowired
    ISalesOrderFlowDomainService salesOrderFlowDomainService;
    @Test
    public void test(){
        ProxyHandler proxyHandler = new ProxyHandler();
        ISalesOrderFlowDomainService iSalesOrderFlowDomainService = (ISalesOrderFlowDomainService) proxyHandler.getProxyHandler(salesOrderFlowDomainService);
        SalesOrderFlowDTO salesOrderFlow = iSalesOrderFlowDomainService.getSalesOrderFlow("20210702000001", OrderFlowType.SIGNED);
        System.out.println(salesOrderFlow);
    }
}

Using Cglib to implement dynamic proxy

Cglib is not a jar package that comes with jdk. It needs to be downloaded and added to the project
CGLIB proxy related classes:

  • net.sf.cglib.proxy.Enhancer is the main enhancement class.
  • net.sf.cglib.proxy.MethodInterceptor is the main method interception class. It is a sub interface of the Callback interface and needs to be implemented by the user.
  • Net.sf.cglib.proxy.methodproxy the proxy class of the java.lang.reflect.Method class of the JDK can easily call the source object methods.

The principle of CGLIB dynamic proxy is to generate a subclass of the original class with Enhancer, and set callback to proxy, then each method call of the original class will be converted to call the intercept() function of the proxy that implements the MethodInterceptor interface

Implement the MethodInterceptor interface

public class CglibProxy implements MethodInterceptor{
    //Main enhancement classes.
    private Enhancer enhancer = new Enhancer();
    @Override
    /**
     * 
     * @param o Is a proxy object
     * @param method Method object that calls the method
     * @param args Method parameters
     * @param methodProxy
     * @return cglib To generate an object instead of the Method object, using the MethodProxy will improve the efficiency of directly executing the Method than calling the JDK's own Method
     * @throws Throwable
     */
    public Object intercept(Object o, Method method, Object[] args,
            MethodProxy methodProxy) throws Throwable {
        System.out.println("before " + methodProxy.getSuperName());  
        System.out.println(method.getName());  
        Object o1 = methodProxy.invokeSuper(o, args);  
        //Object o2 = method.invoke(o, args);  Using this method will cause a life and death cycle, because the method will be intercepted
        System.out.println("after " + methodProxy.getSuperName());  
        return o1;  
    }
    
    public  Object newProxyInstance(Class<?> c) {
        //Sets the parent class of the resulting proxy object.
        enhancer.setSuperclass(c); 
        //Sets an instance of the CallBack interface
        enhancer.setCallback(this);  
        //Creates the target object using the default parameterless constructor 
        return enhancer.create();  
    }
}

Proxied objects and test classes

public class CglibDemo {
    public static void main(String[] args) {
        CglibProxy cglibProxy = new CglibProxy();  
        Do o = (Do)cglibProxy.newProxyInstance(Do.class);  
        System.out.println(o.doSomething(5));
    }
}
class Do{
    public int doSomething(int num){
        System.out.println("Method execution......");
        return num;
    }
}

Difference between Jdk and Cglib

java dynamic proxy uses reflection mechanism to generate an anonymous class that implements the proxy interface. It calls InvokeHandler before calling the specific method. cglib dynamic proxy uses asm open source package to load the class file of proxy object class and generate subclasses by modifying its bytecode.

  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
    spring will automatically convert between JDK dynamic proxy and CGLIB. How to force CGLIB to implement AOP?
  • Add CGLIB library, SPRING_HOME/cglib/*.jar
  • Add < AOP: AspectJ AutoProxy proxy target class = "true" / > to the spring configuration file
    What is the difference between JDK dynamic proxy and CGLIB bytecode generation?
  • JDK dynamic proxy can only generate proxy for classes that implement interfaces, not for classes
  • CGLIB implements a proxy for a class. It mainly generates a subclass of a specified class and overrides the methods in it
    Because it is inheritance, it is best not to declare the class or method as final

[reference article]
[1]https://www.cnblogs.com/shijiaqi1066/p/3429691.html

Posted by ccbayer on Wed, 24 Nov 2021 11:01:48 -0800