How to implement dynamic proxy? What is the difference between JDK Proxy and CGLib

Dynamic proxy

Dynamic proxy is a mechanism for dynamically constructing proxy objects and dynamically calling proxy methods during program operation.

The use of dynamic agents in business is generally to add preprocessing or subsequent operations to the methods that need to be implemented, but does not interfere with the normal business of the implementation class, and separates some basic business from the main business logic. The Spring AOP principle that we generally know is based on dynamic proxy implementation.

The common implementation of dynamic proxy is reflection. The reflection mechanism refers to the ability of a program to access, detect, and modify its own state or behavior during operation. Using reflection, we can call any class object, as well as the properties and methods contained in the class object.

But dynamic proxy is more than just reflection. For example, dynamic proxy can be implemented by CGLib, and CGLib is based on ASM (a Java bytecode manipulation framework) instead of reflection. Simply put, dynamic proxy is a way of behavior, and reflection or ASM is just a means of its realization.

The difference between JDK Proxy and CGLib

JDK Proxy

  • JDK Proxy is a built-in function of the Java language and does not need to be implemented by loading third-party classes;

  • Java provides stable support for JDK Proxy, and will continue to upgrade and update JDK Proxy. For example, the performance of JDK Proxy in the Java 8 version has improved a lot compared to the previous version;

  • JDK Proxy is implemented by interceptor and reflection;

  • JDK Proxy can only proxy classes that inherit interfaces;

  • JDK Proxy is relatively simple to implement and call;

  • CGLib is a tool provided by a third party, implemented based on ASM, with relatively high performance;

  • CGLib does not need to be implemented through an interface, it is called by implementing subclasses.

JDK Proxy code walkthrough

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;

public class JDKProxyLearn {
    
    
    static interface Car{
    
    
        void running();
    }
    static class Bus implements Car{
    
    

        @Override
        public void running() {
    
    
            System.out.println("The Bus is running");
        }
    }

    static class Taxi implements Car{
    
    

        @Override
        public void running() {
    
    
            System.out.println("The Taxi is running");
        }
    }

    //使用JDK Proxy
    static class JDKProxy implements InvocationHandler{
    
    
        private Object target;

        public Object getInstance(Object target){
    
    
            this.target=target;
            return Proxy.newProxyInstance(target.getClass().getClassLoader(),target.getClass().getInterfaces(),this);
            //target.getClass().getClassLoader() 代理类的类加载器
            //target.getClass().getInterfaces()被代理类的接口,如果有多个就是数组形式传入。
            // 代理类实例
        }

        @Override
        public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
    
    
            System.out.println("动态代理之前的业务处理");
            Object result=method.invoke(target,args);//利用反射调用类里面的实际方法
            return result;//方法的返回值,没有就是null
        }
    }

    public static void main(String[] args) {
    
    
        JDKProxy jdkProxy=new JDKProxy();
        Car carInstance =(Car) jdkProxy.getInstance(new Taxi());
        carInstance.running();

    }
}

The core of JDK Proxy's implementation of dynamic proxy is to implement the Invocation interface, which has only one invoke interface.

InvocationHander is a proxy, and the invoke() method is a triggered execution method. It has the capability of a dynamic proxy by implementing the Innovation interface.

CGLib code walkthrough

import net.sf.cglib.proxy.Enhancer;
import net.sf.cglib.proxy.MethodInterceptor;
import net.sf.cglib.proxy.MethodProxy;

import java.lang.reflect.Method;

public class CGLibLearn {
    
    
    static class Car{
    
    
        public void running()
        {
    
    
            System.out.println("The car is running");
        }
    }
    /*CGLib 代理类*/
    static class CGLibProxy  implements MethodInterceptor{
    
    
        private Object target;

        public Object getInstance(Object target)
        {
    
    
            this.target=target;

            Enhancer enhancer=new Enhancer();
            enhancer.setSuperclass(this.target.getClass());
            enhancer.setCallback(this);
            return enhancer.create();
        }

        @Override
        public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
    
    
            System.out.println("CGlib---方法调用前调用方法");
            Object result = methodProxy.invokeSuper(o, objects);
            return result;
        }
    }

    public static void main(String[] args) {
    
    
        CGLibProxy proxy=new CGLibProxy();
        Car car = (Car) proxy.getInstance(new Car());
        car.running();
    }
}

When CGLib initializes the proxy class, it implements dynamic proxy by setting the proxy object as a subclass of the proxy class through the Enhancer object. Therefore, the proxy class cannot be modified by the keyword final. If it is modified by final, an error will be reported when using Enhancer to set the parent class, and the construction of the dynamic proxy will fail.

Dynamic agent knowledge point expansion

What is the difference between dynamic proxy and static proxy? A static proxy is actually a proxy class written in advance, which can be manually written or generated by a tool, but its disadvantage is that each business class must correspond to a proxy class, which is particularly inflexible and inconvenient, so there is a dynamic proxy.

Common usage scenarios of dynamic proxy include RPC framework encapsulation, AOP (Aspect Oriented Programming) implementation, JDBC connection, etc.

Two dynamic proxies, JDK Proxy and CGLib, are used in the Spring framework at the same time. When the Bean implements the interface, Spring will use the JDK Proxy. When the interface is not implemented, it will use CGLib. We can also specify the mandatory use of CGLib in the configuration. Just add <aop:aspectj-autoproxy proxy-target-class=“true”/> in the Spring configuration.

Lombok

The implementation of Lombok has nothing to do with reflection. The implementation of Lombok is completed in the compiler

In fact, Lombok is implemented based on the JSR 269: Pluggable Annotation Processing API implemented by Java 1.6, which is implemented by customizing the annotation processor at compile time. Its execution steps are as follows:

Insert picture description here

It can be seen from the flowchart that during the compilation phase, when the Java source code is abstracted into a syntax tree (AST), Lombok will dynamically modify the AST according to its own annotation processor, add new codes (nodes), and execute all of them. After that, the final bytecode (.class) file is generated, which is the execution principle of Lombok.

Guess you like

Origin blog.csdn.net/tangshuai96/article/details/111335389