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

Java 代理模式深度解析:靜態代理 vs 動態代理 (JDK Proxy)

     編輯:Java 相關知識

代理模式三大角色

  • 抽象角色:定義業務接口(Interface);
  • 真實角色:實現具體業務邏輯;
  • 代理角色:持有真實角色引用,增強預處理/後處理(日誌、事務、權限)。

靜態代理:手寫代理類

interface Business { void doAction(); }

class BusinessImpl implements Business {
    public void doAction() { System.out.println("核心業務邏輯"); }
}

class BusinessImplProxy implements Business {
    private BusinessImpl target;
    public void doAction() {
        if (target == null) target = new BusinessImpl();
        doBefore();
        target.doAction();
        doAfter();
    }
    private void doBefore() { System.out.println("前置增強:開啟事務/記錄日誌"); }
    private void doAfter() { System.out.println("後置增強:提交事務/釋放資源"); }
}

// 客戶端
Business biz = new BusinessImplProxy();
biz.doAction();

痛點:每個業務接口都要手寫一個代理類,代碼膨脹、維護成本高。

動態代理:JDK Proxy 運行時生成代理類

核心組件:

  • java.lang.reflect.Proxy:代理類工廠;
  • java.lang.reflect.InvocationHandler:統一攔截入口。

完整實現

interface BusinessFoo { void foo(); }
interface BusinessBar { String bar(String msg); }

class BusinessFooImpl implements BusinessFoo {
    public void foo() { System.out.println("BusinessFooImpl.foo()"); }
}
class BusinessBarImpl implements BusinessBar {
    public String bar(String msg) { System.out.println("BusinessBarImpl.bar()"); return msg; }
}

// 通用調用處理器
class BusinessInvocationHandler implements InvocationHandler {
    private final Object target;
    public BusinessInvocationHandler(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;
    }

    // 工廠方法:生成代理實例
    public static Object newProxy(Object target) {
        Class clazz = target.getClass();
        return Proxy.newProxyInstance(
            clazz.getClassLoader(),
            clazz.getInterfaces(), // 僅支持接口代理
            new BusinessInvocationHandler(target)
        );
    }
}

// 測試
public class DynamicProxyDemo {
    public static void main(String[] args) {
        BusinessFoo foo = (BusinessFoo) BusinessInvocationHandler.newProxy(new BusinessFooImpl());
        foo.foo();

        BusinessBar bar = (BusinessBar) BusinessInvocationHandler.newProxy(new BusinessBarImpl());
        System.out.println(bar.bar("Hello"));
    }
}

運行流程圖解

client → foo.foo()
        ↓
Proxy 實例 (動態生成 $Proxy0 實現 BusinessFoo)
        ↓
InvocationHandler.invoke(proxy, method, args)
        ↓
前置增強 → method.invoke(target, args) → 後置增強
        ↓
return result

關鍵限制與對比

維度靜態代理JDK 動態代理CGLIB (繼承代理)
代理類生成編譯期手寫運行時字節碼生成運行時子類生成
目標要求實現接口必須實現接口非 final 類
性能直接調用最快反射調用有開銷FastClass 索引較快
適用場景固定少量接口通用 AOP、接口多無接口/第三方類

Spring AOP 底層選型邏輯

  • 目標類實現接口 → JDK Proxy;
  • 目標類無接口 / 強制使用 CGLIB → @EnableAspectJAutoProxy(proxyTargetClass=true)。

理解靜態/動態代理本質,是掌握 Spring AOP、RPC 框架、中間件擴展的基石。

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