動態代理是 Java 基礎框架(Spring AOP、RPC 框架)的基石。本文通過「鏈家中介」的生活場景,層層遞進講解 java.lang.reflect.Proxy 與 InvocationHandler 的協作機制,並給出完整可運行代碼。
invoke(Object proxy, Method method, Object[] args),所有代理方法調用均委派至此。newProxyInstance(ClassLoader, Class[] interfaces, InvocationHandler) 運行時生成代理類字節碼並實例化。LianJia 定義 sellHouse()、loan()。HouseMaster 實現接口,真實業務邏輯。CreatProxy 實現 InvocationHandler,持有目標對象,生成代理。// 1. 業務接口
interface LianJia {
void sellHouse();
void loan();
}
// 2. 真實對象(房東)
class HouseMaster implements LianJia {
public void sellHouse() { System.out.println("我有房子要賣"); }
public void loan() { System.out.println("我要貸款做生意"); }
}
// 3. 動態代理工廠
class CreatProxy implements InvocationHandler {
private Object target;
public Object bind(Object target) {
this.target = target;
return Proxy.newProxyInstance(
target.getClass().getClassLoader(),
target.getClass().getInterfaces(),
this
);
}
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println("【中介】準備辦理:" + method.getName());
Object result = method.invoke(target, args); // 反射調用真實方法
System.out.println("【中介】辦理完成:" + method.getName());
return result;
}
}
// 4. 測試
public class Test {
public static void main(String[] args) {
HouseMaster hm = new HouseMaster();
CreatProxy cp = new CreatProxy();
LianJia proxy = (LianJia) cp.bind(hm);
proxy.sellHouse();
proxy.loan();
}
}
【中介】準備辦理:sellHouse
我有房子要賣
【中介】辦理完成:sellHouse
【中介】準備辦理:loan
我要貸款做生意
【中介】辦理完成:loan
Proxy.newProxyInstance 使用 ASM 等字節碼庫動態生成實現指定接口的類,類名形如 com.sun.proxy.$Proxy0。handler.invoke(this, method, args),將邏輯委派給 InvocationHandler 實現。| 維度 | 靜態代理 | 動態代理 |
|---|---|---|
| 代理類定義 | 編寫 .java 文件,編譯期確定 | 運行時字節碼生成 |
| 靈活性 | 低,每個目標類需寫一個代理類 | 高,一個 Handler 處理多接口 |
| 維護成本 | 高 | 低 |
| 適用範圍 | 固定、少量場景 | 框架級、通用攔截需求 |
動態代理將「什麼時候做什麼事」(業務邏輯)與「如何做增強」(切面邏輯)解耦,是面向切面編程的基石。掌握其原理,有助於深入理解 Spring AOP、Dubbo、MyBatis Mapper 代理等主流框架的核心機制。