An in depth understanding of two ways to implement java dynamic proxies (JDK and Cglib)

  • 2020-06-19 10:13:43
  • OfStack

What is the proxy pattern?

Proxy pattern: Instead of calling the target class directly at the invocation, the proxy class is called, and then the target class is called through the proxy class to do the operation. Some preprocessing and post-processing operations can be added before and after the proxy class calls the target class to complete some functions not belonging to the target class.

Why use proxy mode?

The proxy mode can control the invocation of the target class and carry out some operations not belonging to the target class before and after the invocation of the target class, such as data validation, pre-processing, post-processing, exception handling, etc

What is a static proxy and what is a dynamic proxy?

Static proxy: Proxy classes can only implement proxy classes for specific interfaces Dynamic proxy: Proxy classes can implement multiple types of proxies

What is the difference between jdk agent and cglib agent?

jdk Dynamic proxy: represents all "implemented interfaces" target classes cglib Dynamic proxy: Proxies to any 1 target class, but not to final classes and methods

The difference: The target class of the jdk dynamic proxy must implement an interface because the target class's interface class needs to be passed in when calling ES24en.newProxyInstance (). cglib does not.

Here's the code analysis:

Define an Person interface


package com.zpj.designMode.proxy;

// define 1 a Person interface 
public interface Person {
  public void doWork();
}

Add 1 implementation class: MrLi


package com.zpj.designMode.proxy;

// add 1 An implementation class 
public class MrLi implements Person {

  @Override
  public void doWork() {
    System.out.println("-----doWork");
  }

}

Static agent:

Add 1 static proxy class Proxy


package com.zpj.designMode.proxy;

// Static proxy. The proxy and the target class must implement a common interface 
public class Proxy implements Person {
  private Person person;//  The principal 

  // The target type here determines that the proxy class can only be implemented by proxies Person An instance of an interface that cannot receive arguments of other types, which is the limitation of static proxies 
  public Proxy(Person person) {
    this.person = person;
  }

  @Override
  public void doWork() {
    System.out.println("doSomething-----start");
    person.doWork();
    System.out.println("doSomething-----end");
  }

}

Static proxy tester:


package com.zpj.designMode.proxy;

public class Run {
  public static void main(String[] args) {
    MrLi li = new MrLi();
    Proxy proxy = new Proxy(li);
    // The agent is called directly from the invocation point to perform the operation of the target method. 
    proxy.doWork();
  }
}

JDK Dynamic Agent:

Add a proxy JDKProxy that implements the InvocationHandler interface and overrides the invoke method.


package com.zpj.designMode.proxy.jdk;

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

/***
 @author Perkins Zhu
 @date 2017 years 3 month 13 day   In the morning 8:41:10
 */
public class JDKProxy implements InvocationHandler {

  private Object person;//  The principal 
   
  
  // The target type here is Object , can accept arbitrary 1 As a proxy class, the dynamic proxy is implemented. But pay attention to the following newProxyInstance () 
  public Object getInstance(Object person) {
    this.person = person;
    // with cglib The difference here is that you need to pass in the interface object of the proxy object when you build the proxy object 2 A parameter. while cglib There is no need for the proxy object to implement any interface     
    return Proxy.newProxyInstance(person.getClass().getClassLoader(), person.getClass().getInterfaces(), this);
  }

 

  @Override
  public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
    System.out.println("doSomething---------start");
    method.invoke(person, args);
    System.out.println("doSomething---------end");
    return null;
  }

}

JDK Dynamic Proxy test program


package com.zpj.designMode.proxy.jdk;

import com.zpj.designMode.proxy.MrLi;
import com.zpj.designMode.proxy.Person;

/***
 * @author Perkins Zhu
 * @date 2017 years 3 month 13 day   In the morning 8:51:31
 */
public class Run {

  public static void main(String[] args) {
    Person person = (Person) new JDKProxy().getInstance(new MrLi());
    // Notice that the person Not the target class person , but the proxy class person : debug Time display null , there are '$' identifier 
    person.doWork();
  }
}

Cglib Dynamic Proxy:

Add 1 CglibProxy agent and implement the MethodInterceptor interface.


package com.zpj.designMode.proxy.cglib;

import java.lang.reflect.Method;

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

/***
 * @author Perkins Zhu
 * @date 2017 years 3 month 13 day   In the morning 9:02:54
 */
public class CglibProxy implements MethodInterceptor {
  private Object targetObject;

  //  The target type here is Object , can accept arbitrary 1 As a proxy class, the dynamic proxy is implemented 
  public Object getInstance(Object target) {
    this.targetObject = target;
    Enhancer enhancer = new Enhancer();
    enhancer.setSuperclass(target.getClass());
    enhancer.setCallback(this);
    // Note the creation of the agent there 
    Object proxyObj = enhancer.create();
    return proxyObj;//  Return the proxy object 
  }

  @Override
  public Object intercept(Object proxy, Method method, Object[] args, MethodProxy methodProxy) throws Throwable {
    Object obj = null;
    System.out.println("doSomething---------start");
    obj = method.invoke(targetObject, args);
    System.out.println("doSomething---------end");
    return obj;
  }

}

Cglib Dynamic Proxy tester


package com.zpj.designMode.proxy.cglib;

import com.zpj.designMode.proxy.MrLi;
import com.zpj.designMode.proxy.Person;

/***
 @author Perkins Zhu
 @date 2017 years 3 month 13 day   In the morning 9:07:38
 */
public class Run {

  public static void main(String[] args) {
    Person person = (Person)new CglibProxy().getInstance(new MrLi());
    person.doWork();
  }
}

Carefully compare the differences and similarities between Proxy, CglibProxy and JDKProxy in distinguishing static agents, JDK dynamic agents and Cglib dynamic agents!


Related articles: