Implementation of Spring JDK agent and CGLIB agent

JDK agent:

JDK dynamic proxy is also implemented by basic interface. Because the interface points to the polymorphic way of implementing class instance, it can effectively decouple the specific implementation and call, and facilitate the later modification and maintenance.

  1. To create a "Car" interface:
package com.example.demo;

/**
 * Define Car interface
 */
public interface Car {
    void whatCar();
}

2. Create "Mazda" class, implement interface "Car", and implement method "whatCar":

package com.example.demo;

public class Mazda implements Car {
    @Override
    public void whatCar() {
        System.out.println("I am Mazda");
    }
}

3. To create a dynamic proxy class, you need to implement the InvocationHandler interface. There are detailed comments in the code:

package com.example.demo;

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

/**
 * To create a dynamic proxy class, you need to implement the InvocationHandler interface
 */
public class CarInvocationHandler implements InvocationHandler{

    //Represented object is real object
    private Object target;

    Object bind(Object target) {
        this.target = target;
        /* Proxy.newProxyInstance Parameter interpretation:
         * The first is the class loader, which is the class loader of the class itself
         * The second is the interfaces to which the generated dynamic proxy objects are attached. This is the interface implemented by obj. In this paper, the Car interface
         * The third is to define the proxy class that implements the method logic, and the method of which class will pass in which class
         */
        return Proxy.newProxyInstance(target.getClass().getClassLoader(),target.getClass().getInterfaces(),this);
    }

    /**
     * Proxy method: when we use the proxy object to schedule real objects, it will enter the invoke method
     * @param proxy Method called proxy instance, proxy class
     * @param method Current scheduling objects
     * @param args Parameters for method calls
     * @return
     * @throws Throwable
     */
    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        System.out.println("----Call preprocessing");
        //Reflect the original method
        Object invoke = method.invoke(target, args);
        System.out.println("----Post call processing");
        return invoke;
    }
}

4.main method:

public static void main(String[] args){
   Mazda mazda = new Mazda();
   CarInvocationHandler aih = new CarInvocationHandler();
   //Return interface type, similar to @ Autowired
   Car mazdaBind = (Car) aih.bind(mazda);
   mazdaBind.whatCar();
}

When calling mazdaBind.whatCar(), it will go to invoke()
This is the basic principle of AOP implementation, but Spring does not need to be maintained by developers themselves.

5. Output results:

CGLIB agent:

cglib dynamic proxy enhances the target class by implementing subclasses.
for instance:
If you want to know who is the Avengers, you have to find Nick (Avengers method interceptor), and Nick goes to find the hero, and let him tell you which hero he is.

1. Create the "TheAvengers" class:

package com.example.demo;

public class TheAvengers {
    public void whichHero(){
        System.out.println("I am Iron Man");
    }
}

2. Create the "avengersmethodeinterceptor" class, implement the MethodInterceptor interface, and intercept the methods of the proxy object:

package com.example.demo.cglib;

import org.springframework.cglib.proxy.MethodInterceptor;
import org.springframework.cglib.proxy.MethodProxy;
import java.lang.reflect.Method;

/**
 * cglib Implement dynamic proxy to intercept the method of the proxy object
 */
public class AvengersMethodInterceptor implements MethodInterceptor {
    /*
     * Object: cglib Generated proxy objects
     * Method: Methods of proxied objects
     * Object[]: Method parameter
     * MethodProxy: Method of proxy object
     */
    @Override
    public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
        System.out.println("Before calling");
        Object obj = methodProxy.invokeSuper(o,objects); //Invokeseuper: calls the original (parent) method on the specified object.
        System.out.println("After calling");
        return obj;
    }
}

3. Create "CGLIBTest" test class:

package com.example.demo.cglib;

import org.springframework.cglib.proxy.Enhancer;

public class CGLIBTest {

    public static void main(String[] args){
        // The process of obtaining proxy object through CGLIB dynamic proxy
        Enhancer en = new Enhancer();
        // Set the parent of the enhancer object
        en.setSuperclass(TheAvengers.class);
        // Set the callback object of enhancer
        en.setCallback(new AvengersMethodInterceptor());
        // Create proxy object
        TheAvengers avengers = (TheAvengers)en.create();
        // Call target method through proxy object
        avengers.whichHero();
    }

}

When the target method (avengers.whichHero();) is called through a proxy object, it enters the intercept method in avengersmethodeinterceptor.

4. The results are as follows:

Approximate process

  1. Set parent class (target class), callback object (method interceptor), and generate bytecode file of agent class
  2. Using ClassLoader to load bytecode files into the JVM
  3. Create the proxy class instance object and execute the target method of the object

Reference blog:
https://blog.csdn.net/yu_kang/article/details/88530016
https://www.cnblogs.com/godoforange/p/11587321.html

Published 28 original articles, won praise 18, visited 9002
Private letter follow

Tags: Java JDK Spring jvm

Posted on Sat, 11 Jan 2020 03:41:58 -0500 by nekoanz