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

Java 靜態代理模式完整指南:從基礎實現到進階應用

     編輯:Java 相關知識

靜態代理:AOP 思想的最直觀體現

靜態代理是設計模式中代理模式的一種,核心思想是:在不修改目標對象代碼的前提下,為其添加額外功能。這正是面向切面編程 (AOP) 的基石——將橫切關注點 (日誌、事務、權限、緩存) 與業務邏輯分離。

基礎實現:手動包裝目標對象

// 1. 定義共同介面
public interface UserDao {
    void save();
    void update();
}

// 2. 目標對象 - 純業務邏輯
public class UserDaoImpl implements UserDao {
    @Override
    public void save() {
        System.out.println("保存用戶數據...");
    }
    @Override
    public void update() {
        System.out.println("更新用戶數據...");
    }
}

// 3. 代理對象 - 增強功能
public class UserDaoProxy implements UserDao {
    private UserDao target; // 持有目標對象引用
    
    public UserDaoProxy(UserDao target) {
        this.target = target;
    }
    
    @Override
    public void save() {
        System.out.println("【代理】開啟事務");
        target.save(); // 呼叫目標方法
        System.out.println("【代理】提交事務");
    }
    
    @Override
    public void update() {
        System.out.println("【代理】記錄日誌");
        target.update();
        System.out.println("【代理】權限校驗");
    }
}

// 4. 客戶端使用
public class Client {
    public static void main(String[] args) {
        UserDao target = new UserDaoImpl();
        UserDao proxy = new UserDaoProxy(target);
        proxy.save(); // 實際執行代理增強後的邏輯
    }
}

進階痛點:代碼重複與耦合問題

隨著方法增多,每個代理方法都要重複寫「開啟事務 → 調用目標 → 提交事務」,導致:

  • 大量樣板代碼,維護成本高
  • 代理類與目標類強耦合 (需知曉目標具體類)
  • 每新增一個目標類,就得寫一個對應代理類

改良方案:反射 + 調用處理器 (JDK 動態代理雛形)

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;

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

// 使用 JDK 動態代理生成代理對象
UserDao target = new UserDaoImpl();
UserDao proxy = (UserDao) Proxy.newProxyInstance(
    target.getClass().getClassLoader(),
    target.getClass().getInterfaces(),
    new TransactionHandler(target)
);
proxy.save(); // 自動應用事務增強

靜態代理 vs 動態代理 核心對比

維度靜態代理JDK 動態代理CGLIB 動態代理
代理類生成時間編譯期運行時運行時
目標類要求無特殊要求必須實作介面無介面要求 (繼承子類)
代碼複用性低高 (通用 Handler)高
效能最高 (直接調用)反射開銷FastClass 機制,較快
適用場景固定、少量增強介面導向、通用增強無介面、高效能需求

Spring AOP 的選擇邏輯

  • 目標類實作介面 → 優先 JDK 動態代理
  • 目標類無介面 / 強制使用 CGLIB → 使用 CGLIB (繼承子類代理)
  • 可通過 @EnableAspectJAutoProxy(proxyTargetClass=true) 強制 CGLIB

靜態代理的現代價值

雖然生產環境多用動態代理,但靜態代理仍有教學與特定場景價值:

  1. 理解代理本質: 最清晰展示「包裝、轉發、增強」核心流程
  2. 編譯期檢查: 類型安全,IDE 友好,重構無風險
  3. 特定增強場景: 僅需為極少數方法添加特定邏輯,動態代理反而過度設計
  4. 原始碼可見: 便於除錯、審計、安全合規要求

掌握靜態代理,是通往動態代理、AOP 框架原理、Spring 核心機制的必經之路。

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