This is the 20th day of my participation in the Genwen Challenge


Ninety percent of programmers use dynamic proxies directly or indirectly, whether it’s the logging framework or the Spring framework, which includes the code to implement dynamic proxies. Dynamic proxy is a mechanism by which a program dynamically builds proxy objects and invokes proxy methods during runtime.

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

answer

A common implementation of dynamic proxies is reflection. Reflection mechanism refers to the ability of program to access, detect and modify its own state or behavior during running. With reflection, we can call any class object, as well as the properties and methods contained in the class object.

But there is more to dynamic proxies than reflection. For example, dynamic proxies can be implemented using CGLib, which is based on ASM (a Java bytecode manipulation framework) rather than reflection. Simply put, dynamic proxy is a mode of behavior, and reflection or ASM is just a means of implementing it.

JDK Proxy differs from CGLib in the following ways

  • JDK Proxy is a built-in function of the Java language, which does not need to load third-party classes.
  • Java provides stable support for JDK Proxies and will continue to upgrade and update JDK Proxies. For example, JDK Proxy performance in Java 8 has improved significantly compared to previous versions.
  • JDK Proxy is implemented by interceptor plus reflection;
  • JDK Proxies can only Proxy classes that inherit interfaces;
  • JDK Proxy is simple to implement and invoke;
  • CGLib is a third-party tool based on ASM with high performance.
  • CGLib does not require an interface; it makes calls by implementing subclasses.

The test analysis

The interview questions are about your understanding of reflection, dynamic proxy, and CGLib. Many people often equate reflection with dynamic proxy, but in a strict sense, this idea is not correct. To really understand the relationship between them, also shows that you have solid Java basic skills. Here are a few things you can learn from this question:

  • Knowledge of JDK Proxy and CGLib.
  • Is Lombok implemented through reflection?
  • What is the difference between dynamic and static proxies?
  • What are the use scenarios for dynamic proxies?
  • How is dynamic proxy implemented in Spring?

Knowledge extension

1. Use and code analysis of JDK Proxy and CGLib

JDK Proxy dynamic Proxy implementation

JDK Proxy dynamic Proxy implementation does not need to reference third-party classes, just need to implement the InvocationHandler interface, override the invoke() method, the entire implementation code is as follows:

/** * JDK Proxy examples */
public class ProxyExample {
    static interface Car {
        void running(a);
    }

    static class Bus implements Car {
        @Override
        public void running(a) {
            System.out.println("The bus is running."); }}static class Taxi implements Car {
        @Override
        public void running(a) {
            System.out.println("The taxi is running."); }}/** * JDK Proxy */
    static class JDKProxy implements InvocationHandler {
        private Object target; // Proxy object

        // Get the proxy object
        public Object getInstance(Object target) {
            this.target = target;
            // Get the proxy object
            return Proxy.newProxyInstance(target.getClass().getClassLoader(),
                    target.getClass().getInterfaces(), this);
        }

        /** * Execute the proxy method *@paramProxy Proxy object *@paramMethod Proxy method *@paramParameter * to the args method@return
         * @throws InvocationTargetException
         * @throws IllegalAccessException
         */
        @Override
        public Object invoke(Object proxy, Method method, Object[] args)
                throws InvocationTargetException, IllegalAccessException {
            System.out.println("Business processing before dynamic proxy.");
            Object result = method.invoke(target, args); // Execute the calling method (before and after this method is executed, relevant business processing can be done)
            returnresult; }}public static void main(String[] args) {
        // Execute JDK Proxy
        JDKProxy jdkProxy = new JDKProxy();
        Car carInstance = (Car) jdkProxy.getInstance(newTaxi()); carInstance.running(); }}Copy the code

The execution result of the above procedure is:

Business processing before dynamic proxy. The taxi is running.Copy the code

Invoke () method Invocation Invocation Invocation Invocation Invocation Invocation Invocation Invocation Invocation Invocation Invocation Invocation

public interface InvocationHandler {
  public Object invoke(Object proxy, Method method, Object[] args)
          throws Throwable;
}
Copy the code

This is because there is an important role in the dynamic proxy, the proxy, which is used to centrally manage the prostedobject. Obviously InvocationHandler is this proxy, and the invoke() method is the execution method that triggers the proxy. We have dynamic proxy capability by implementing the Invocation interface.

The implementation of additional

Before using CGLib, we need to introduce the CGLib framework in our project and add the following configuration to pom.xml:

<dependency>
    <groupId>cglib</groupId>
    <artifactId>cglib</artifactId>
    <version>3.3. 0</version>
</dependency>
Copy the code

CGLib implementation code is as follows:

public class CGLibExample {

    static class Car {
        public void running(a) {
            System.out.println("The car is running."); }}/** * CGLib proxy class */
    static class CGLibProxy implements MethodInterceptor {
        private Object target; // Proxy object

        public Object getInstance(Object target) {
            this.target = target;
            Enhancer enhancer = new Enhancer();
            // Set the parent class to the instance class
            enhancer.setSuperclass(this.target.getClass());
            // Callback method
            enhancer.setCallback(this);
            // Create a proxy object
            return enhancer.create();
        }

        @Override
        public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
            System.out.println("Business processing before method call.");
            Object result = methodProxy.invokeSuper(o, objects); // Perform the method call
            returnresult; }}// Execute the CGLib method call
    public static void main(String[] args) {
        Create a CGLib proxy class
        CGLibProxy proxy = new CGLibProxy();
        // Initialize the proxy object
        Car car = (Car) proxy.getInstance(new Car());
        // Execute methodcar.running(); }}Copy the code

The execution result of the above procedure is:

Business processing before method invocation. The car is running.Copy the code

It can be seen that CGLib and JDK Proxy implementation code is similar, both through the implementation of the interface of the Proxy, and then call a method to complete the dynamic Proxy, the only difference is that when CGLib initializes the proxied class, Dynamic proxying is implemented by setting the proxy object as a subclass of the propped class through the Enhancer object. Therefore, the proxyed class cannot be modified by the keyword final. If it is modified by final, an error will be reported when setting the parent class using Enhancer, and the dynamic proxy will fail to be built.

2.Lombok principle analysis

Before I dive into Lombok, let’s briefly introduce Lombok, a popular Java utility class that can be used to effectively solve tedious and repetitive code in code engineering. Setters, getters, toString, equals, hashCode, and so on can all be done with Lombok annotations to this method.

For example, we use a lot of setters and getters. Before Lombok, the code would look like this:

public class Person {
    private Integer id;
    private String name;
    public Integer getId(a) {
        return id;
    }
    public void setId(Integer id) {
        this.id = id;
    }
    public String getName(a) {
        return name;
    }
    public void setName(String name) {
        this.name = name; }}Copy the code

After using Lombok, the code looks like this:

@Data
public class Person {
    private Integer id;
    private String name;
}
Copy the code

You can see Lombok makes the code much simpler and more elegant.

If Lombok’s Getter and Setter annotations are used in your project, then to successfully call the set or GET methods of an object during the coding phase, Lombok plug-ins need to be installed in the IDE, such as the Idea plugin shown in the following figure:

Here’s how Lombok works.

The implementation of Lombok has nothing to do with reflection. We said that reflection is a function of introspect at runtime, but Lombok is implemented at compile time.

Going back to the Setter/Getter method, when you open the compiled class for Person, you’ll find Lombok’s @data annotation in the source code:

Lombok generates the corresponding bytecode for us at compile time.

Lombok is based on the JSR 269: Pluggable Annotation Processing API implemented in Java 1.6, which uses a compile-time custom Annotation processor to perform the following steps:

As you can see from the flowcharts, Lombok dynamically modifies the AST at compile time, adding new code (nodes) based on its annotation handlers, after the Java source code has been abstracted into a syntax tree (AST), and then generates the final bytecode (.class) file. This is how Lombok works.

3. Dynamic proxy knowledge expansion

When interviewers ask about dynamic agents, they often ask the difference between dynamic agents and static agents. Static proxy is actually a pre-written proxy class, which can be manually written or generated using tools. But its disadvantage is that each business class has to correspond to a proxy class, which is particularly inflexibly and inconvenient, so there is a dynamic proxy.

Dynamic proxies are commonly used in RPC framework encapsulation, AOP (aspect oriented programming) implementation, JDBC connectivity, and so on.

The Spring framework uses both JDK Proxy and CGLib as dynamic proxies. Spring uses JDK Proxy when the Bean implements the interface, and CGLib when the Bean does not implement the interface. We can also specify that CGLib is mandatory in the configuration. Just add < AOP: Aspectj-autoproxy proxy-target-class=”true”/> to your Spring configuration.

summary

JDK Proxy is a dynamic Proxy built into Java language. It must implement interfaces to Proxy related classes. CGLib is an efficient dynamic Proxy class provided by a third party based on ASM. It implements dynamic proxying by implementing subclasses of proxied classes, so that proxied classes cannot use final modifiers.

In addition to JDK Proxy and CGLib, it also introduces the implementation principle of Lombok, a common tool class in Java, which has nothing to do with reflection. Finally, the dynamic proxy application scenarios and Spring dynamic proxy implementation, I hope this article can help you.