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

Java 動態代理機制深度解析:JDK Proxy 與 InvocationHandler 核心原理

     編輯:Java 相關知識

靜態代理 vs 動態代理

靜態代理:代理類在編譯期確定,.class 文件已存在。
動態代理:代理類在運行時通過反射動態生成字節碼,無需預先定義代理類文件。JDK 動態代理基於接口,核心類為 java.lang.reflect.Proxy 和 InvocationHandler。

核心組件架構

// 1. 業務接口
public interface Service {
    void add();
    void update();
}

// 2. 目標實現
public class AService implements Service {
    public void add() { System.out.println("AService add"); }
    public void update() { System.out.println("AService update"); }
}

// 3. 調用處理器(核心邏輯)
public class MyInvocationHandler implements InvocationHandler {
    private Object target;  // 被代理對象
    
    public MyInvocationHandler(Object target) { this.target = target; }
    
    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        System.out.println("before-----------------------------"); // 前置增強
        Object result = method.invoke(target, args);               // 調用目標方法
        System.out.println("after------------------------------");  // 後置增強
        return result;
    }
}

// 4. 客戶端使用
public class Client {
    public static void main(String[] args) {
        Service target = new AService();
        MyInvocationHandler handler = new MyInvocationHandler(target);
        
        // 動態生成代理實例
        Service proxy = (Service) Proxy.newProxyInstance(
            target.getClass().getClassLoader(),
            target.getClass().getInterfaces(),
            handler
        );
        
        proxy.add();    // 輸出: before -> AService add -> after
        proxy.update(); // 輸出: before -> AService update -> after
    }
}

Proxy.newProxyInstance 核心流程源碼解讀

  1. getProxyClass:生成實現指定接口的代理類 Class 對象
  2. ProxyGenerator.generateProxyClass:核心字節碼生成邏輯,輸出 byte[]
  3. defineClass0:本地方法將字節碼定義為 JVM 類
  4. Constructor.newInstance:實例化代理類,注入 InvocationHandler

生成代理類結構示例(反編譯視角)

public final class $Proxy0 extends Proxy implements Service {
    protected $Proxy0(InvocationHandler h) { super(h); }
    
    public final void add() {
        try {
            super.h.invoke(this, m3, null); // m3 為 add 方法的 Method 對象
        } catch (Error | RuntimeException e) { throw e; }
        catch (Throwable t) { throw new UndeclaredThrowableException(t); }
    }
    
    public final void update() { /* 類似結構 */ }
    // equals、hashCode、toString 也被重寫委託給 handler
}

關鍵點:代理類繼承 Proxy、實現目標接口、構造器接收 InvocationHandler、所有接口方法重寫為調用 handler.invoke()。

關鍵限制與注意事項

  • 只能代理接口:無法代理普通類(需 CGLIB/ByteBuddy)
  • 方法調用開銷:反射調用比直接調用慢,高頻熱點路徑需權衡
  • final 方法不攔截:Object 的 final 方法(如 getClass)不會進入 invoke
  • 序列化支持:代理類實現 Serializable 需 handler 也可序列化

典型應用場景

  • Spring AOP 事務管理、日誌攔截、權限校驗
  • RPC 框架客戶端存根生成
  • API 閘關請求/響應過濾
  • 測試 Mock 框架底層實現
  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved