靜態代理是設計模式中代理模式的一種,核心思想是:在不修改目標對象代碼的前提下,為其添加額外功能。這正是面向切面編程 (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(); // 實際執行代理增強後的邏輯
}
}
隨著方法增多,每個代理方法都要重複寫「開啟事務 → 調用目標 → 提交事務」,導致:
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(); // 自動應用事務增強
| 維度 | 靜態代理 | JDK 動態代理 | CGLIB 動態代理 |
|---|---|---|---|
| 代理類生成時間 | 編譯期 | 運行時 | 運行時 |
| 目標類要求 | 無特殊要求 | 必須實作介面 | 無介面要求 (繼承子類) |
| 代碼複用性 | 低 | 高 (通用 Handler) | 高 |
| 效能 | 最高 (直接調用) | 反射開銷 | FastClass 機制,較快 |
| 適用場景 | 固定、少量增強 | 介面導向、通用增強 | 無介面、高效能需求 |
@EnableAspectJAutoProxy(proxyTargetClass=true) 強制 CGLIB雖然生產環境多用動態代理,但靜態代理仍有教學與特定場景價值:
掌握靜態代理,是通往動態代理、AOP 框架原理、Spring 核心機制的必經之路。