Design pattern -- agent pattern

Posted by lmhart on Wed, 15 Dec 2021 08:43:46 +0100

proxy pattern

Proxy mode provides a proxy for other objects to control access to this object. Proxy mode provides a proxy object for an object, and the proxy object controls the reference to the original object. Generally speaking, the agency model is a common intermediary in our life.

Sample code

Common interface between proxy class and real class

public interface Subject {
    void request();
}

Real class request

public class RealSubject implements Subject{
    @Override
    public void request() {
        System.out.println("Real request");
    }
}

Proxy request, the real class object is introduced, and the method is enhanced

public class Proxy implements Subject{

    private RealSubject realSubject;

    @Override
    public void request() {
        if (realSubject == null) {
            realSubject = new RealSubject();
        }
        realSubject.request();
        System.out.println("Proxy request");
    }
}

Main function test

public class JavaDemo {

    public static void main(String[] args){
        Subject proxy = new Proxy();
        proxy.request();
    }
}

Static proxy

Static proxy: it is created by programmers or automatically generated by specific tools, that is, the interface, proxy class and proxy class have been determined at compile time. The name of the proxy class before the program runs The class file has been generated.

Simple implementation of static proxy

If the students of a class want to pay the class fee to the teacher, but they all pass their money to the teacher through the monitor. Here, the monitor acts as an agent for students to pay class fees, and the monitor is the agent of students.

1. Determine the specific behavior of creating an interface

First, we create a Person interface. This interface is the public interface between the student (represented class) and the monitor (agent class). They all have the behavior of paying the shift fee. In this way, the student's shift fee can be executed by the monitor.

/**
 * Create Person interface
 */
public interface Person {
    //Turn in the shift fee
    void giveMoney();
}

2. The proxy object implements the interface and completes the specific business logic

The student class implements the Person interface. Student can specifically implement the action of shift handover fee:

public class Student implements Person {
    private String name;
    public Student(String name) {
        this.name = name;
    }
    
    @Override
    public void giveMoney() {
       System.out.println(name + "Shift handover fee: 50 yuan");
    }
    }

3. The agent class implements the interface to complete the pre-processing messages, filtering messages, forwarding messages to the delegate class, and post-processing messages of the delegate class.

StudentsProxy class, which also implements the Person interface, but also holds a student class object. Since the Pearson interface is implemented and a student object is held at the same time, he can execute the shift fee (execute the giveMoney() method) on behalf of the student class object.

/**
 * The student agent class also implements the Person interface to save a student entity, which can act as a proxy for students
 * @author Gonjan
 *
 */
public class StudentsProxy implements Person{
    //Represented student
    Student stu;
    
    public StudentsProxy(Person stu) {
        // Delegate student objects only
        if(stu.getClass() == Student.class) {
            this.stu = (Student)stu;
        }
    }
    
    //Delegate the shift fee and call the shift fee behavior of the delegated student
    public void giveMoney() {
        stu.giveMoney();
    }
}

4. Client operation and analysis

public class StaticProxyTest {
    public static void main(String[] args) {
        //Zhang San, the student being represented, handed over his class fee to the agent monitor (monitor) for completion
        Person zhangsan = new Student("Zhang San");
        
        //Generate a proxy object and pass Zhang San to the proxy object
        Person monitor = new StudentsProxy(zhangsan);
        
        //Shift handover fee for the agent of the monitor
        monitor.giveMoney();
    }
    }

Instead of directly implementing the shift fee through Zhang San (the agent), it is implemented through the monitor (the agent). This is the agent mode.

The most important thing of proxy mode is that there is a public interface (Person), a specific class (Student) and a proxy class (StudentsProxy), the proxy class holds the instance of the concrete class and executes the instance method of the concrete class on its behalf. As mentioned above, the proxy mode introduces a certain degree of indirectness when accessing the actual object, because this indirectness can be used for a variety of purposes. The indirectness here refers to not directly calling the method of the actual object, so we can add one in the proxy process Some other uses. For example, before joining the monitor to help Zhang San pay the shift fee, I want to reflect that Zhang San has made great progress in his recent study, which can be easily achieved through the agent mode:

public class StudentsProxy implements Person{
    //Represented student
    Student stu;
    
    public StudentsProxy(Person stu) {
        // Delegate student objects only
        if(stu.getClass() == Student.class) {
            this.stu = (Student)stu;
        }
    }
    
    //Delegate the shift fee and call the shift fee behavior of the delegated student
    public void giveMoney() {
        System.out.println("Zhang San has made progress in his study recently!");
        stu.giveMoney();
    }
}

Just perform other operations before Zhang San's shift fee in the agent class. This operation is also a great advantage of using proxy mode

The most straightforward is aspect oriented programming (AOP) in Spring. We can perform some operations before and after a pointcut. This pointcut is a method.

Dynamic agent

Introduction to dynamic agent

JDK dynamic proxy can only generate proxy for classes that implement interfaces, not for classes

principle

An interceptor (interceptor must implement InvocationHanlder) and a reflection mechanism are used to generate an anonymous class that implements the proxy interface. InvokeHandler is invoked before calling the specific method.

Code simulation dynamic agent process

Interface of the proxy object:

//Teacher's interface
public interface IteachDao
{
    void teach();
    Integer getTeachersAge(String name);
}

Specific proxy object

public class TeachDao implements IteachDao
{

    @Override
    public void teach() {
        System.out.println("In the teacher's teaching.....");
    }

    @Override
    public Integer getTeachersAge(String name) {
        return 18;
    }
}

Agent factory

public class ProxyFactory
{
      //Maintain a target Object -- Object
    private  Object object;
    //Constructor to initialize the target object
    public ProxyFactory(Object object)
    {
        this.object=object;
    }
    //Generate a proxy object for the target object
     public Object getProxyInstance()
    {
//        public static Object newProxyInstance(ClassLoader loader,
//            Class<?>[] interfaces,
//            InvocationHandler h)
        //1. Classloader: Specifies the class loader used by the current object and the method to obtain the class loader
        //2.Class<?> [] interfaces: the interface type implemented by the target object. Use the generic method to confirm the type
        //3.InvocationHandler h: event handler method will be triggered when executing the method of the target object
        //The currently executed target object method will be passed in as a parameter
        return Proxy.newProxyInstance(object.getClass().getClassLoader(),
                object.getClass().getInterfaces(),
                //Anonymous inner class
                new InvocationHandler() {
                    @Override
                    //Proxy: is the proxy object, and method is the method currently executed by the proxy object
                    //args: parameters of the executed method
                    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
                        System.out.println("JDK Agent start");
                        //Reflection mechanism calls the method of the target object -- returns the return value of the original method
                        System.out.println("Current method:"+method);
                        System.out.println("Current method parameters:"+args);
                        Object invoke = method.invoke(object, args);
                        //Return method return value
                        return invoke;
                    }
                });
    }
}

test

public class test
{
    @Test
    public void test()
    {
        //Create target object
        IteachDao t=new TeachDao();
         //Create a proxy object for the target object
        IteachDao proxyInstance=(IteachDao)new ProxyFactory(t).getProxyInstance();
        System.out.println("===================Next, print the proxy object and get type===========================");
        System.out.println(proxyInstance);
        System.out.println(proxyInstance.getClass());//Get type
        System.out.println("=====================Get the teacher's age below=====================================");
        proxyInstance.getTeachersAge("Huyou ");
        System.out.println("======================Output teacher in class=======================================");
        proxyInstance.teach();
    }
}

Dynamic agent jdk source code flow analysis

Related classes and interfaces

To understand the mechanism of Java Dynamic Proxy, you first need to understand the following related classes or interfaces:

  1. java.lang.reflect.Proxy: This is the main class of Java dynamic proxy mechanism. It provides a set of static methods to dynamically generate proxy classes and their objects for a set of interfaces

  2. java.lang.reflect.InvocationHandler: This is the calling processor interface. It defines an invoke method to handle several method calls on dynamic proxy class objects. Proxy access to the delegate class is usually implemented in this method.

  3. java.lang.ClassLoader: the dynamic Proxy class generated by Proxy static method also needs to be loaded through the class loader. The only difference between it and ordinary classes is that its bytecode is dynamically generated by the JVM at runtime rather than pre stored in any one Class file.

Agency mechanism and its characteristics

First, let's learn how to use Java dynamic proxy. There are four steps as follows:

  1. Create your own calling processor by implementing the InvocationHandler interface;
  2. Create a dynamic Proxy class by specifying a ClassLoader object and a set of interface s for the Proxy class;
  3. The constructor of the dynamic proxy class is obtained through the reflection mechanism, and its only parameter type is the calling processor interface type;
  4. The dynamic proxy class instance is created through the constructor, and the calling processor object is passed in as a parameter during construction.
// InvocationHandlerImpl implements the InvocationHandler interface and can dispatch and forward method calls from proxy class to delegate class
// It usually contains a reference to the instance of the delegate class, which is used to actually execute the method call forwarded by the dispatch
InvocationHandler handler = new InvocationHandlerImpl(..); 

// Dynamically create the class object of Proxy class for a group of interfaces including Interface interface through Proxy
Class clazz = Proxy.getProxyClass(classLoader, new Class[] { Interface.class, ... }); 

// Get the constructor object from the generated class object by reflection
Constructor constructor = clazz.getConstructor(new Class[] { InvocationHandler.class }); 

// Create a dynamic proxy class instance through a constructor object
Interface Proxy = (Interface)constructor.newInstance(new Object[] { handler });

We can print it into the file by the following methods to see the true face:

/**
 * Create Person interface
 */
public interface Person {
    //Turn in the shift fee
    void giveMoney();
}


public class Student implements Person {
    private String name;
    public Student(String name) {
        this.name = name;
    }
    
    @Override
    public void giveMoney() {
        try {
            //Suppose it took a second to count the money
            Thread.sleep(1000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
       System.out.println(name + "Shift handover fee: 50 yuan");
    }
}


public class MonitorUtil {
    
    private static ThreadLocal<Long> tl = new ThreadLocal<>();
    
    public static void start() {
        tl.set(System.currentTimeMillis());
    }
    
    //Printing time at end
    public static void finish(String methodName) {
        long finishTime = System.currentTimeMillis();
        System.out.println(methodName + "Method time consuming" + (finishTime - tl.get()) + "ms");
    }
}


public class StuInvocationHandler<T> implements InvocationHandler {
    //Proxied object held by invocationHandler
    T target;
    
    public StuInvocationHandler(T target) {
       this.target = target;
    }
    
    /**
     * proxy:Represents a dynamic proxy object
     * method: Represents the method being executed
     * args: Represents the argument passed in when the target method is called
     */
    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        System.out.println("Agent execution" +method.getName() + "method");  
        //The monitoring method is inserted in the agent process, and the calculation of this method is time-consuming
        MonitorUtil.start();
        Object result = method.invoke(target, args);
        MonitorUtil.finish(method.getName());
        return result;
}
byte[] classFile = ProxyGenerator.generateProxyClass("$Proxy0",Student.class.getInterfaces());
String path = "G:/javacode/javase/Test/bin/proxy/StuProxy.class";
try(FileOutputStream fos = new FileOutputStream(path)) {
    fos.write(classFile);
    fos.flush();
    System.out.println("proxy class class File written successfully");
} catch (Exception e) {
    System.out.println("Write file error");
}

Decompile this class file. Let's see what jdk generates for us:

public final class $Proxy0 extends Proxy implements Person {
  private static Method m1;
  private static Method m2;
  private static Method m3;
  private static Method m0;
  
  /**
  *Note that this is the construction method of generating proxy class. The method parameter is InvocationHandler type. Do you understand this
  *Why does the proxy object always execute the invoke method in the InvocationHandler, and the InvocationHandler holds one
  *The instance of the proxy object can't help but wonder if it is? Yes, that's what you think.
  *
  *super(paramInvocationHandler),Is the constructor that calls the parent class Proxy.
  *Parent class holding: protected InvocationHandler h;
  *Proxy Construction method:
  *    protected Proxy(InvocationHandler h) {
  *         Objects.requireNonNull(h);
  *         this.h = h;
  *     }
  *
  */
  public $Proxy0(InvocationHandler paramInvocationHandler)
    throws 
  {
    super(paramInvocationHandler);
  }
  
  //This static block was originally at the end. I brought it to the front for easy description
   static
  {
    try
    {
      //Look at what's in the static block here. Did you find the giveMoney method. Remember the name given by giveMoney through reflection m3, and ignore the others first
      m1 = Class.forName("java.lang.Object").getMethod("equals", new Class[] { Class.forName("java.lang.Object") });
      m2 = Class.forName("java.lang.Object").getMethod("toString", new Class[0]);
      m3 = Class.forName("proxy.Person").getMethod("giveMoney", new Class[0]);
      m0 = Class.forName("java.lang.Object").getMethod("hashCode", new Class[0]);
      return;
    }
    catch (NoSuchMethodException localNoSuchMethodException)
    {
      throw new NoSuchMethodError(localNoSuchMethodException.getMessage());
    }
    catch (ClassNotFoundException localClassNotFoundException)
    {
      throw new NoClassDefFoundError(localClassNotFoundException.getMessage());
    }
  }
 
  /**
  * 
  *Here, the giveMoney method of the proxy object is called, which directly calls the invoke method in the InvocationHandler and passes m3 in.
  *this.h.invoke(this, m3, null);It's simple and clear.
  *Now, think again, the proxy object holds an InvocationHandler object, and the InvocationHandler object holds an object to be proxied,
  *Then contact the invoke method in the InvacationHandler. Well, that's it.
  */
  public final void giveMoney()
    throws 
  {
    try
    {
      this.h.invoke(this, m3, null);
      return;
    }
    catch (Error|RuntimeException localError)
    {
      throw localError;
    }
    catch (Throwable localThrowable)
    {
      throw new UndeclaredThrowableException(localThrowable);
    }
  }
 
  //Note that toString, hashCode and equals methods are omitted to save space. The principle is the same as the giveMoney method.
}

jdk generated a $Proxy0 for our (0 after the name is the number, and multiple proxy classes will increase at one time). This class file is placed in memory. When we create a proxy object, we obtain the construction method of this class through reflection, and then create the proxy instance. Through the view of the generated proxy class source code, we can easily see the specific implementation of dynamic proxy Cheng.

We can think of InvocationHandler as an intermediary class, and the intermediary class holds a proxy object and invokes the corresponding method of the proxy object in the invoke method. Hold the reference of the proxy object through aggregation, and finally turn the external call to invoke into the call to the proxy object.

When the proxy class calls its own method, it calls the invoke method of the mediation class object through its own mediation class object, so as to achieve the proxy to execute the method of the proxy object. In other words, the dynamic agent realizes the specific agent function through the intermediary class.

Summary: the generated Proxy class: $Proxy0 extends Proxy implements Person. We can see that the Proxy class inherits the Proxy class, so it determines that the Java dynamic Proxy can only Proxy the interface. The inheritance mechanism of Java doomed these dynamic Proxy classes to be unable to implement the dynamic Proxy to the class. The above example of dynamic agent is actually a simple implementation of AOP. It is processed before and after the method of the target object is executed, and the time consumption of the method is counted. Spring's AOP implementation actually uses Proxy and InvocationHandler.

InvocationHandler interface and Proxy class

InvocationHandler interface is an interface implemented by the calling handler of proxy proxy instance. Each proxy instance has an associated calling handler; When a method is called by a proxy instance, the method call is encoded and dispatched to the invoke method of the calling handler.

When we call a method through a dynamic proxy object, the call of this method will be forwarded to the invoke method implementing the InvocationHandler interface class to call, as shown in the following invoke method:

    /**
    * proxy:The real proxy object of proxy class proxy com sun. proxy.$ Proxy0
    * method:The Method object of the real Method of an object we want to call
    * args:Refers to the parameters passed by the proxy object method
    */
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable;

Proxy class is a class used to create a proxy object. It provides many methods, but the most commonly used method is newProxyInstance.

public static Object newProxyInstance(ClassLoader loader, 
                                            Class<?>[] interfaces, 
                                            InvocationHandler h)

The function of this method is to create a proxy class object, which receives three parameters. Let's look at the meaning of the following parameters:

  • loader: a classloader object that defines which classloader object loads the generated proxy class
  • Interfaces: an array of interface objects, which indicates what kind of interfaces we will provide to our proxy object. If we provide such an array of interface objects, we declare that the proxy class implements these interfaces, and the proxy class can call all the methods declared in the interface.
  • h: An InvocationHandler object indicates which InvocationHandler object will be associated with when the method is called by the dynamic proxy object, and finally called by it.

JDK dynamic agent summary

Some characteristics of dynamically generated proxy class itself

  1. Package: if all the interfaces represented are public, Then it will be defined in the top-level package (that is, the package path is empty). If there are non-public interfaces in the proxy interface (because the interface cannot be defined as protect or private, it is the default package access level except public. Then it will be defined in the package where the interface is located. The purpose of this design is to ensure that the dynamic agent class will not be successfully defined and accessed due to package management problems to the greatest extent;

  2. Class modifier: the proxy class has final and public modifiers, which means that it can be accessed by all classes, but cannot be inherited again;

  3. Class name: the format is "$ProxyN", where N is an Arabic numeral increasing one by one, representing the dynamic Proxy class generated by the Proxy class for the nth time. It is worth noting that the value of N will not increase every time the static method of Proxy is called to create a dynamic Proxy class, The reason is that if you try to repeatedly create a dynamic Proxy class for the same group of interfaces (including the same order of interfaces), it will intelligently return the class object of the previously created Proxy class instead of trying to create a new Proxy class, which can save unnecessary code generation and improve the efficiency of Proxy class creation.

  4. Class inheritance: Proxy class is its parent class. This rule applies to all dynamic Proxy classes created by Proxy. Moreover, the class also implements a set of interfaces it represents;

Some characteristics of proxy class instances

  1. Each instance will be associated with an InvocationHandler (calling processor object). When the proxy class instance calls the method declared in its proxy interface, it will eventually be executed by the invoke method of InvocationHandler;
  2. java. Three methods in lang.Object will also be dispatched to the invoke method of the calling processor for execution. They are hashCode, equals and toString;
    A set of characteristics of a proxied interface
  3. Note that there can be no duplicate interfaces
  4. Interfaces must be visible to the class loader, otherwise the class loader will not be able to link them
  5. All non-public interfaces to be proxied must be in the same package, and the number of interfaces cannot exceed 65535

a fly in the ointment

Proxy can only proxy the interface, but cannot dynamically proxy the class. By observing the dynamically generated proxy inheritance diagram, we can see the reason. They already have a fixed parent class called proxy, and Java syntax limits that they can no longer inherit other parent classes

The returned dynamic proxy object is an object that implements all the interfaces implemented by the proxy object. Therefore, it is not possible to call the additional content of the proxy object or convert the proxy object to the type of the proxy object. This will report an error

Cglib agent

introduce

CGLIB is a powerful high-performance code generation package.

CGLIB implements a proxy for a class. It mainly generates a subclass of a specified class and overrides its methods (inheritance);

Using ASM open source package, load the class file of proxy object class, and generate subclasses by modifying its bytecode.

  • It is widely used by many AOP frameworks, such as Spring AOP and dynaop, which provide them with method interception;
  • hibernate uses CGLIB to proxy single ended (many to one and one to one) associations (delayed fetching of sets is implemented by other mechanisms)
  • EasyMock and jMock are packages that test java code by using mock objects.
  • They all use CGLIB to create mock objects for classes without interfaces.

Import related dependencies in maven project

    <dependency>
        <groupId>cglib</groupId>
        <artifactId>cglib</artifactId>
        <version>3.3.0</version>
    </dependency>

Code demonstration

Proxied object

public class TeachDao
{

    public void teach() {
        System.out.println("In the teacher's teaching.....");
    }
    public Integer getTeachersAge(String name) {
        return 18;
    }
    public void show()
    {
        System.out.println("Hello");
    }
}

Generate and process proxy object factory classes for related logic

//Implement the MethodInterceptor interface
public class ProxyFactory implements MethodInterceptor
{
    //Target object requiring proxy
private  Object target;
    ProxyFactory(Object target)
    {
        this.target=target;
    }
    //Method to get proxy object
    public Object getProxyInstance()
    {
        // The process of obtaining proxy objects through CGLIB dynamic proxy
        Enhancer enhancer=new Enhancer();
        // Set the parent class of enhancer object. Since Cglib generates a subclass for the specified class, you need to specify the parent class
        enhancer.setSuperclass(target.getClass());
        //Sets the callback object for enhancer
        enhancer.setCallback(this);
        // Create proxy object
        return enhancer.create();
    }
    /**
     * @param o cglib Generated proxy object
     * @param method Method of proxy object
     * @param objects     Parameters passed in to the method
     * @param methodProxy Proxy method
     */
    @Override//Override intercept method
    public Object intercept(Object o, Method method, Object[] objects,
                            MethodProxy methodProxy) throws Throwable {
        System.out.println("cglib Agent in...");
        //Method for executing the proxy object - Method 1
        System.out.println("======================");
        System.out.println("The method of executing the proxied object in the process of dynamic proxy");
        //The proxy object must be passed in here, or it will loop
        //Because proxy object method calls trigger interceptors
        Object ret= method.invoke(target, objects);
        System.out.println("The return value of the method of the proxy object:"+ret);
        System.out.println("======================");
        return ret;

        //Mode II
        //The following writing will cause an endless loop because calling the proxied method will trigger the interceptor
        //Object invoke = methodProxy.invoke(o, objects);
        //Therefore, it should be the method of executing the parent class -- here the proxy object must be passed in
        //Object invokeSuper = methodProxy.invokeSuper(o, objects);
        //return invokeSuper;// Return method return value
    }
}

test

public class test
{
    @Test
    public void test()
    {
       //Get proxy object
        ProxyFactory proxyFactory=new ProxyFactory(new TeachDao());
        TeachDao proxyInstance = (TeachDao)proxyFactory.getProxyInstance();
        //Executing the method of the proxy object will trigger the intercept method to call the target object
         proxyInstance.teach();
         proxyInstance.show();
        Integer age = proxyInstance.getTeachersAge("Huyou ");
        System.out.println(age);
    }
}

Method filter (CallbackFilter)

CGlib provides us with a method filter (CallbackFilter), which can clearly indicate which interceptor intercepts different methods in the proxy class.

public class MyProxyFilter implements CallbackFilter {
//Get all the methods of the current object, including equals
//toString
//hashCode
//clone
    @Override
    public int accept(Method method) {
        //If the method is called show
        if(method.getName().equals("show"))
            return 0;//Let the first interceptor handle it
        return 1;//Let the second interceptor handle it
    }
}

Add an instance generation method with filter in the workshop

    //Method to get proxy object
    public Object getProxyInstance()
    {
        // The process of obtaining proxy objects through CGLIB dynamic proxy
        Enhancer enhancer=new Enhancer();
        // Set the parent class of enhancer object. Since Cglib generates a subclass for the specified class, you need to specify the parent class
        enhancer.setSuperclass(target.getClass());
        //Sets the callback object for enhancer
        //this interceptor calls the overridden Intercept method
        enhancer.setCallbacks(new Callback[]{this, NoOp.INSTANCE});
        //catalog filter
        enhancer.setCallbackFilter(new MyProxyFilter());
        // Create proxy object
        return enhancer.create();
    }

The interceptors used are defined in setCallbacks, where NOOP Instance is provided by CGlib, which is actually an interceptor without any operation,
They are orderly and must be in the same order as the CallbackFilter. The return (0 / 1) above is the order of return. That is, if the show method is called, this is used for interception.

Test:

//Get proxy object
        ProxyFactory proxyFactory=new ProxyFactory(new TeachDao());
        TeachDao proxyInstance = (TeachDao)proxyFactory.getProxyInstance();
        System.out.println("use intercept Interceptor to intercept");
         proxyInstance.show();
        System.out.println("use NoOp.INSTANCE,Empty implementation interceptor");
        proxyInstance.teach();

Implementation principle

CGLib uses the underlying bytecode technology ASM to create a subclass for a class. In the subclass, the method interception technology is used to intercept the calls of all parent class methods and weave into the crosscutting logic.

What is intercepted here is the generated proxy object, that is, the method called by the subclass. The subclass inherits all the methods of the parent class and calls the parent class method in disguise

JDK and CGLIB dynamic agent summary

  • JDK dynamic agent can only generate agents for classes that implement interfaces, not for classes. It is implemented using Java reflection technology, and the process of generating classes is more efficient.
  • CGLIB implements a proxy for a class. It mainly generates a subclass of a specified class and covers its methods. It is implemented using the asm bytecode framework. The related execution process is more efficient. The process of generating a class can be compensated by the cache. Because it is inheritance, it is better not to declare this class or method as final
  • JDK proxy does not need the support of a third-party library. It can be used only in the JDK environment. Usage conditions: implement InvocationHandler + use proxy Newproxyinstance generates proxy object + the proxied object must implement the interface
  • CGLib must rely on CGLib's class library, but it needs classes to implement any interface proxy. It generates a subclass from the specified class and overrides the methods in it. It is an inherited proxy, but it is recommended to use JDK in the environment of interface programming;
  • For classes and methods marked with final, static methods can not implement dynamic proxy, which is related to the underlying principle of java

Reference articles

Java Dynamic Proxy analysis

CGLIB details

Introduction to cglib dynamic agent

Principle and implementation of CGLib dynamic agent based on MAVEN project

Agent mode Usage Summary

Topics: Java