核心類結構
// 1. 業務介面
public interface BusinessProcessor {
void processBusiness();
}
// 2. 真實實現
public class BusinessProcessorImpl implements BusinessProcessor {
@Override
public void processBusiness() {
System.out.println("processing business.....");
}
}
// 3. 代理處理器(核心邏輯)
public class BusinessProcessorHandler implements InvocationHandler {
private Object target;
public BusinessProcessorHandler(Object target) {
this.target = target;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println("前置增強:處理業務前...");
Object result = method.invoke(target, args); // 反射調用真實對象
System.out.println("後置增強:處理業務後...");
return result;
}
}
// 4. 客戶端使用
public class Test {
public static void main(String[] args) {
BusinessProcessorImpl real = new BusinessProcessorImpl();
BusinessProcessorHandler handler = new BusinessProcessorHandler(real);
BusinessProcessor proxy = (BusinessProcessor) Proxy.newProxyInstance(
real.getClass().getClassLoader(),
real.getClass().getInterfaces(),
handler
);
proxy.processBusiness();
// 觀察生成的代理類
System.out.println(proxy.getClass().getName()); // $Proxy0
printClassDefinition(proxy.getClass());
}
}
運行輸出與生成類結構
前置增強:處理業務前...
processing business.....
後置增強:處理業務後...
$Proxy0
$Proxy0 extends java.lang.reflect.Proxy implements com.fans.common.proxy.BusinessProcessor
{
java.lang.reflect.Method m1;
java.lang.reflect.Method m3;
java.lang.reflect.Method m0;
java.lang.reflect.Method m2;
boolean equals(java.lang.Object);
java.lang.String toString();
int hashCode();
void processBusiness();
}
Proxy.newProxyInstance 三步驟深度解析
- 動態生成字節碼: 根據
interfaces 參數,生成實現所有介面的類,繼承 Proxy,重寫 equals/hashCode/toString,核心邏輯委派給 InvocationHandler.invoke
- 類載入: 使用指定
ClassLoader 將生成的 byte[] 定義為類($Proxy0)
- 實例化: 調用構造函數
$Proxy0(InvocationHandler),初始化 Method 成員變量(緩存介面方法),返回代理實例
客戶端調用鏈路
proxy.processBusiness()
→ $Proxy0.processBusiness()
→ handler.invoke(proxy, method, args)
→ method.invoke(target, args) // 反射調用真實對象
→ 返回結果
關鍵設計點
| 特性 | 說明 |
| 介面驅動 | 只能代理介面,無法代理類(需 CGLIB/ByteBuddy) |
| 單一 InvocationHandler | 所有方法調用統一進入 invoke(),需自行判斷 method |
| Method 緩存 | 代理類建構時預先解析並緩存 Method 物件 |
| 不可序列化 | 動態代理類預設不實現 Serializable |
進階應用模式
1. 多介面代理
proxy = (InterfaceA & InterfaceB) Proxy.newProxyInstance(
loader, new Class[]{InterfaceA.class, InterfaceB.class}, handler);
2. 方法級過濾
if (method.getName().startsWith("get")) {
return cache.get(method); // 讀方法走緩存
}
return method.invoke(target, args); // 寫方法穿透
3. 異常統一處理
try {
return method.invoke(target, args);
} catch (InvocationTargetException e) {
throw e.getCause(); // 解包真實異常
}
對比:JDK Proxy vs CGLIB
| 維度 | JDK Proxy | CGLIB |
| 代理目標 | 介面 | 類(繼承) |
| final 方法 | 可代理 | 不可代理 |
| 生成方式 | 介面實現 | 子類繼承 |
| 效能 | 調用稍慢(反射) | FastClass 機制較快 |
| Spring 預設 | 有介面用 JDK | 無介面用 CGLIB |
最佳實踐建議
- 優先面向介面編程,天然支援 JDK 動態代理
- 代理邏輯保持輕量,避免在
invoke 做重運算
- 大量代理場景考慮緩存
Method、使用 MethodHandle 提升效能
- Spring AOP 底層即基於此機制,理解原理有助於排查代理失效問題