首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> Java 程式設計 >> Java 程式設計入門

Java 動態代理深度實戰:JDK Proxy 機制、InvocationHandler 與生成類結構解析

     編輯:Java 程式設計入門

核心類結構


// 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 三步驟深度解析

  1. 動態生成字節碼: 根據 interfaces 參數,生成實現所有介面的類,繼承 Proxy,重寫 equals/hashCode/toString,核心邏輯委派給 InvocationHandler.invoke
  2. 類載入: 使用指定 ClassLoader 將生成的 byte[] 定義為類($Proxy0)
  3. 實例化: 調用構造函數 $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 ProxyCGLIB
代理目標介面類(繼承)
final 方法可代理不可代理
生成方式介面實現子類繼承
效能調用稍慢(反射)FastClass 機制較快
Spring 預設有介面用 JDK無介面用 CGLIB

最佳實踐建議

  1. 優先面向介面編程,天然支援 JDK 動態代理
  2. 代理邏輯保持輕量,避免在 invoke 做重運算
  3. 大量代理場景考慮緩存 Method、使用 MethodHandle 提升效能
  4. Spring AOP 底層即基於此機制,理解原理有助於排查代理失效問題
  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved