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
-
Return value origin – Determine the return value
return Proxy.newProxyInstance(classLoader, interfaces,this)
Proxy.newProxyInstance The return is $Proxy0 object
-
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
-
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
-
Use idea The tool extracts the file
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