普通測試場景
- 業務場景
保存訂單信息 - 分層模型
IOrderService -> OrderServiceImpl - 業務代碼
public class OrderServiceImpl implements IOrderService {
// spring 會自己注入,這裏手動注入
private IOrderDao iOrderDao;
@Override
public int saveOrder(Order order) {
iOrderDao = new OrderDaoImpl();
// 暫時不連接數據庫
return 1;
}
}
- 應用層代碼
public class Test {
public static void main(String[] args) throws Throwable {
IOrderService orderServiceDynamicProxy
= (IOrderService) new OrderServiceDynamicProxy( new OrderServiceImpl()).bind();
// 數據準備
Order order = new Order();
// 使用動態代理存數據
orderServiceDynamicProxy.saveOrder(order);
}
}
- 自定義的代理代碼
實現 InvocationHandler 即可成爲動態代理類, 爲什麼? 需要分析源碼
public class OrderServiceDynamicProxy implements InvocationHandler {
// 被代理的對象, 抽象成Object類, 甚至可以不是接口,提高了最大的靈活性
private Object target;
/**
* 核心方法 -- 動態生成被代理類
* @return JVM生成的 $proxy0 文件
*/
public Object bind(){
// 獲取代理類的class文件
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;
}
/**
* 核心方法 -- 需要debug確定該方法的作用
* @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源碼分析 – debug
-
返回值起源 – 確定返回值
return Proxy.newProxyInstance(classLoader, interfaces,this)
Proxy.newProxyInstance 返回的是 $Proxy0對象
-
返回值追蹤 – 定位類
Proxy類擁有創造前綴爲$Proxy 的工廠內部類(jdk1.8)確定返回值來源類: java.lang.reflect.Proxy.ProxyClassFactory
-
返回值追蹤 – 定位語句
639行出現了一個字節數組,爲proxyClassFile,幾乎能斷定這是動態生成的 $proxy0 字節碼文件
-
使用idea工具提取該文件
FileOutputStream fos = new FileOutputStream("D:\\b.class"); fos.write(proxyClassFile);
2 生成的 $proxy0 源碼
public final class $Proxy0 extends Proxy implements IOrderService {
private static Method m3;
/**
* 構造方法傳入InvocationHandler的實現類
* todo 傳入InvocationHandler 的實現類 OrderServiceDynamicProxy
*
* @param var1 OrderServiceDynamicProxy
*/
public $Proxy0(InvocationHandler var1) {
super(var1);
}
/**
*
* 程序調用的是這個方法,而真正執行的是 OrderServiceDynamicProxy 的 saveOrder 方法
* todo 動態生成的 saveOrder() 方法實際調用的是 OrderServiceDynamicProxy 的invoke方法
* todo invoke 方法是約定而成的模板方法
*
* @param var1 在靜態代碼塊中獲得的參數列表
*
*/
public final int saveOrder(Order methodVar) throws Throwable { // 參數列表的數量和類型也是從class文件中獲取的
// protected InvocationHandler h;
// todo h 是父類Proxy類的成員變量,也就是構造時傳入的 OrderServiceDynamicProxy
return (Integer) super.h.invoke(this, m3, new Object[]{methodVar});
}
/**
* todo 靜態代碼塊先執行
*/
static {
try {
m3 = Class.forName("com.structural.proxy.IOrderService").getMethod("saveOrder", Class.forName("com.structural.proxy.Order"));
}catch (Exception var2) {
var2.printStackTrace();
}
}
}
3 $proxy0 源碼分析
靜態代碼塊通過反射獲取調用者的class文件信息
/**
* todo 靜態代碼塊先執行
*/
static {
try {
m3 = Class.forName("com.structural.proxy.IOrderService").getMethod("saveOrder", Class.forName("com.structural.proxy.Order"));
}catch (Exception var2) {
var2.printStackTrace();
}
}
突破口1 —— $proxy0 的成員方法是由應用層決定
自定義的bind方法中存在以下邏輯,可以確定 $proxy0 內的方法不需要事先知道,
在應用層調用的時候傳入對象,使用對象的class文件可以反射獲取
// 調用bind方法的應用層
IOrderService orderServiceDynamicProxy
= (IOrderService) new OrderServiceDynamicProxy( new OrderServiceImpl()).bind();
// 代理類構造方法
public OrderServiceDynamicProxy(Object target) {
this.target = target;
}
// bind方法邏輯
Class cls = target.getClass();
ClassLoader classLoader = cls.getClassLoader();
Class[] interfaces = cls.getInterfaces(); // 決定了 $Proxy0 implement IOrderService
return Proxy.newProxyInstance(classLoader, interfaces,this);
突破口2 —— InvocationHandler
Proxy.newProxyInstance(,,this)
this 指的是 OrderServiceDynamicProxy implments InvocationHandler
public $Proxy0(InvocationHandler var1) {
super(var1);
}
public final int saveOrder(Order methodVar) throws Throwable {
// protected InvocationHandler h;
// todo h 是父類Proxy類的成員變量,也就是構造時傳入的 OrderServiceDynamicProxy
return (Integer) super.h.invoke(this, m3, new Object[]{methodVar});
}
super.h.invoke(this, m3, new Object[]{methodVar} )
等價於
OrderServiceDynamicProxy.invoke(this, m3, new Object[]{methodVar})
則應用層
public class Test {
public static void main(String[] args) throws Throwable {
IOrderService orderServiceDynamicProxy
= (IOrderService) new OrderServiceDynamicProxy( new OrderServiceImpl()).bind();
// 數據準備
Order order = new Order();
// 使用動態代理存數據
orderServiceDynamicProxy.saveOrder(order);
}
}
orderServiceDynamicProxy.saveOrder(order)
內部調用的是
OrderServiceDynamicProxy.invoke(this, m3, new Object[]{order})
突破口3 —— OrderServiceDynamicProxy.invoke 與 動態代理的關係
動態代理類只要實現Invoke方法,並且確保method.invoke(target, args)即可代理target的所有方法, 還可以加上自己的前置和後置處理,強制代理類實現的原因是:
$Proxy0 的生成模板有super.h.invoke(this, m3, new Object[]{…args})
所以應用層需要適配這個實現
/**
* 核心方法 -- 需要debug確定該方法的作用
* @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;
}
總結
動態代理的實現核心是 藉助 $Proxy0 在運行時生成一個被代理類的class文件,代理類不需要在編譯時寫死被代理類
實現 InvocationHandler 是讓動態代理強制適配 $Proxy0 的生成規則
能夠做到在應用層動態決定被代理類,起到決定性的技術是反射