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

Java 動態代理完整比較:JDK Proxy 與 CGLIB 實作原理、代碼範例與效能選擇建議

     編輯:Java 相關知識

JDK 動態代理 (基於介面)

  • 核心:java.lang.reflect.Proxy + InvocationHandler
  • 限制:**目標類必須實作一或多個介面**
  • 原理:運行時生成實現目標介面的匿名類,委派給 InvocationHandler.invoke。

程式碼範例

// 介面
public interface Calculator { int add(int a, int b); int sub(int a, int b); }

// 實作
public class CalculatorImpl implements Calculator { ... }

// 代理處理器
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("前置: " + method.getName());
        Object result = method.invoke(target, args);
        System.out.println("後置: " + method.getName());
        return result;
    }
}

// 使用
Calculator target = new CalculatorImpl();
Calculator proxy = (Calculator) Proxy.newProxyInstance(
    target.getClass().getClassLoader(),
    target.getClass().getInterfaces(),
    new MyInvocationHandler(target)
);
proxy.add(1, 2); // 輸出前置/後置並返回 3

CGLIB 動態代理 (基於繼承)

  • 第三方庫 (net.sf.cglib),Spring 內建。
  • 原理:生成目標類的**子類**,覆寫非 final 方法攔截呼叫。
  • 限制:無法代理 final 類、final 方法、private 方法。
  • 優點:目標類**不需實作介面**即可代理。

程式碼範例

public class CglibProxy implements MethodInterceptor {
    private Object target;
    public Object getInstance(Object target) {
        this.target = target;
        Enhancer enhancer = new Enhancer();
        enhancer.setSuperclass(target.getClass());
        enhancer.setCallback(this);
        return enhancer.create();
    }
    @Override
    public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable {
        System.out.println("CGLIB 前置");
        Object result = proxy.invokeSuper(obj, args); // 呼叫父類方法
        System.out.println("CGLIB 後置");
        return result;
    }
}

// 使用
CalculatorImpl target = new CalculatorImpl();
CalculatorImpl proxy = (CalculatorImpl) new CglibProxy().getInstance(target);
proxy.add(10, 20);

效能與選擇建議

維度JDK ProxyCGLIB
代理類型介面代理類繼承代理
生成代理速度快慢 (需字節碼操作)
代理方法調用速度較慢 (反射調用)快 (FastClass 機制索引調用)
適用場景單例、長生命週期物件 (一次生成多次調用)頻繁創建代理、目標無介面

Spring 預決策:目標有介面用 JDK,無介面用 CGLIB (可強制 proxy-target-class=true)。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved