• 周六. 10 月 5th, 2024

5G编程聚合网

5G时代下一个聚合的编程学习网

热门标签

【java_ Design pattern] JDK dynamic proxy source code analysis, debug to get $proxy0

King Wang

1 月 3, 2022

Common test scenarios

  • Business scenario
    Save order information
  • Layered model
    IOrderService -> OrderServiceImpl
  • Business code
public class OrderServiceImpl implements IOrderService {

// spring It will inject itself , Here's manual injection 
private IOrderDao iOrderDao;
@Override
public int saveOrder(Order order) {

iOrderDao = new OrderDaoImpl();
// Don't connect to the database for the time being 
return 1;
}
}
  • Application layer code
public class Test {

public static void main(String[] args) throws Throwable {

IOrderService orderServiceDynamicProxy
= (IOrderService) new OrderServiceDynamicProxy( new OrderServiceImpl()).bind();
// Data preparation 
Order order = new Order();
// Use dynamic proxy to store data 
orderServiceDynamicProxy.saveOrder(order);
}
}
  • Custom proxy code

Realization InvocationHandler It becomes a dynamic proxy class , Why? ? need Analysis of the source code

public class OrderServiceDynamicProxy implements InvocationHandler {

// The proxied object , Abstract into Object class , It can't even be an interface , Increased maximum flexibility 
private Object target;
/**
* The core approach -- Dynamically generate the surrogate class
* @return JVM Generated $proxy0 file
*/
public Object bind(){

// Get the... Of the proxy class class file 
Class cls = target.getClass();
ClassLoader classLoader = cls.getClassLoader();
Class[] interfaces = cls.getInterfaces();
return Proxy.newProxyInstance(classLoader, interfaces,this);
}
public OrderServiceDynamicProxy(Object target) {

this.target = target;
}
/**
* The core approach -- need debug Determine the effect of this method
* @param proxy
* @param method
* @param args
* @return
* @throws Throwable
*/
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {

Object argObject = args[0];
beforeMethod(argObject);
Object object = method.invoke(target, args);
afterMethod();
return object;
}
private void beforeMethod(Object obj){
}
private void afterMethod(){
}
}

1 jdk Source code analysis – debug

  1. Return value origin – Determine the return value
    return Proxy.newProxyInstance(classLoader, interfaces,this)

    Proxy.newProxyInstance The return is $Proxy0 object
     Insert picture description here

  2. Return value tracking – Positioning class
    Proxy Class has the creation prefix $Proxy Factory internal class of (jdk1.8)

    Determine the source class of the return value : java.lang.reflect.Proxy.ProxyClassFactory

     Insert picture description here

  3. Return value tracking – Positioning statements

    639 A byte array appears in the row , by proxyClassFile, It’s almost certain that this is dynamically generated $proxy0 Bytecode file
     Insert picture description here


  1. Use idea The tool extracts the file

     Insert picture description here

    FileOutputStream fos = new FileOutputStream("D:\\b.class");
    fos.write(proxyClassFile);
    

2 Generated $proxy0 Source code

public final class $Proxy0 extends Proxy implements IOrderService {

private static Method m3;
/**
* Construction method passed in InvocationHandler Implementation class of
* todo Pass in InvocationHandler Implementation class of OrderServiceDynamicProxy
*
* @param var1 OrderServiceDynamicProxy
*/
public $Proxy0(InvocationHandler var1) {

super(var1);
}
/**
*
* This method is called by the program , And the real implementation is OrderServiceDynamicProxy Of saveOrder Method
* todo Dynamically generated saveOrder() Method actually calls OrderServiceDynamicProxy Of invoke Method
* todo invoke Method is an agreed template method
*
* @param var1 The list of parameters obtained in the static code block
*
*/
public final int saveOrder(Order methodVar) throws Throwable {
 // The number and type of the parameter list are also derived from class Obtained in the file 
// protected InvocationHandler h;
// todo h Parent class Proxy Member variables of class , That's what's passed in during construction OrderServiceDynamicProxy
return (Integer) super.h.invoke(this, m3, new Object[]{
methodVar});
}
/**
* todo Static code blocks are executed first
*/
static {

try {

m3 = Class.forName("com.structural.proxy.IOrderService").getMethod("saveOrder", Class.forName("com.structural.proxy.Order"));
}catch (Exception var2) {

var2.printStackTrace();
}
}
}

3 $proxy0 Source code analysis

Static code blocks get the caller’s class file information

 /**
* todo Static code blocks are executed first
*/
static {

try {

m3 = Class.forName("com.structural.proxy.IOrderService").getMethod("saveOrder", Class.forName("com.structural.proxy.Order"));
}catch (Exception var2) {

var2.printStackTrace();
}
}
breakthrough 1 —— $proxy0 The membership method of is determined by the application layer

Self defined bind The following logic exists in the method , Can be determined $proxy0 There is no need to know in advance ,
Pass in the object when the application layer calls , Using the class Files can be retrieved by reflection

// call bind The application layer of the method 
IOrderService orderServiceDynamicProxy
= (IOrderService) new OrderServiceDynamicProxy( new OrderServiceImpl()).bind();
// Proxy class constructor 
public OrderServiceDynamicProxy(Object target) {

this.target = target;
}
// bind Method logic 
Class cls = target.getClass();
ClassLoader classLoader = cls.getClassLoader();
Class[] interfaces = cls.getInterfaces(); // To determine the $Proxy0 implement IOrderService
return Proxy.newProxyInstance(classLoader, interfaces,this);

breakthrough 2 —— InvocationHandler

Proxy.newProxyInstance(,,this)
this refer to OrderServiceDynamicProxy implments InvocationHandler

 public $Proxy0(InvocationHandler var1) {

super(var1);
}
 public final int saveOrder(Order methodVar) throws Throwable {

// protected InvocationHandler h;
// todo h Parent class Proxy Member variables of class , That's what's passed in during construction OrderServiceDynamicProxy
return (Integer) super.h.invoke(this, m3, new Object[]{
methodVar});
}

super.h.invoke(this, m3, new Object[]{methodVar} )
Equivalent to
OrderServiceDynamicProxy.invoke(this, m3, new Object[]{methodVar})
Then the application layer

public class Test {

public static void main(String[] args) throws Throwable {

IOrderService orderServiceDynamicProxy
= (IOrderService) new OrderServiceDynamicProxy( new OrderServiceImpl()).bind();
// Data preparation 
Order order = new Order();
// Use dynamic proxy to store data 
orderServiceDynamicProxy.saveOrder(order);
}
}

orderServiceDynamicProxy.saveOrder(order)
The internal call is
OrderServiceDynamicProxy.invoke(this, m3, new Object[]{order})

breakthrough 3 —— OrderServiceDynamicProxy.invoke And Dynamic agent relationships

Dynamic proxy classes only need to implement Invoke Method , And make sure that method.invoke(target, args) You can represent target Of All the methods , You can also add your own pre – and post – processing , The reason for forcing proxy class implementation is :
$Proxy0 The generation templates for are super.h.invoke(this, m3, new Object[]{…args})
So the application layer needs to adapt to this implementation

 /**
* The core approach -- need debug Determine the effect of this method
* @param proxy
* @param method
* @param args
* @return
* @throws Throwable
*/
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {

Object argObject = args[0];
beforeMethod(argObject);
Object object = method.invoke(target, args);
afterMethod();
return object;
}

summary

The core of dynamic proxy implementation is With the help of $Proxy0 Generate a surrogate class at run time class file , Proxy classes don’t need to write to the surrogate class at compile time
Realization InvocationHandler Is to make dynamic proxy force fit $Proxy0 The generation rules of
It can dynamically determine the proxy class in the application layer , The decisive technology is reflection

发表回复