// 接口
interface CountDao { void queryCount(); }
// 目標實現
class CountDaoImpl implements CountDao {
public void queryCount() { System.out.println("查看賬戶..."); }
}
// 事務代理
class CountTxProxy implements CountDao {
private final CountDao target;
CountTxProxy(CountDao target) { this.target = target; }
public void queryCount() {
System.out.println("tx begin");
target.queryCount();
System.out.println("tx commit");
}
}
// 日誌代理
class CountLogProxy implements CountDao {
private final CountDao target;
CountLogProxy(CountDao target) { this.target = target; }
public void queryCount() {
System.out.println("log start");
target.queryCount();
System.out.println("log end");
}
}
CountDao dao = new CountDaoImpl();
CountDao tx = new CountTxProxy(dao);
CountDao log = new CountLogProxy(tx); // 外層日誌,內層事務
log.queryCount();
// log start → tx begin → 查看賬戶 → tx commit → log end
**優點**:結構清晰、編譯期類型安全。
**缺點**:每新增一個橫切關注點需手寫代理類、組合代碼冗長、目標類必須實現接口。
class LoggingInvocationHandler implements InvocationHandler {
private final Object target;
LoggingInvocationHandler(Object target) { this.target = target; }
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println("before: " + method.getName());
Object result = method.invoke(target, args);
System.out.println("after: " + method.getName());
return result;
}
}
// 使用
CountDao dao = (CountDao) Proxy.newProxyInstance(
CountDao.class.getClassLoader(),
new Class[]{CountDao.class},
new LoggingInvocationHandler(new CountDaoImpl()));
dao.queryCount();
限制:**目標類必須實現接口**,無法代理普通類。
Enhancer enhancer = new Enhancer();
enhancer.setSuperclass(CountDaoImpl.class); // 針對具體類
enhancer.setCallback(new MethodInterceptor() {
@Override
public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable {
System.out.println("cglib before");
Object result = proxy.invokeSuper(obj, args); // 調用父類方法
System.out.println("cglib after");
return result;
}
});
CountDao proxy = (CountDao) enhancer.create();
proxy.queryCount();
原理:生成目標類子類,攔截父類方法調用。**不能代理 final 類/方法**。
| 維度 | 靜態代理 | JDK 動態代理 | CGLIB |
|---|---|---|---|
| 代理類生成時機 | 編譯期 | 運行時 | 運行時 |
| 目標類要求 | 實現接口 | 實現接口 | 非 final 類 |
| 多橫切點組合 | 手動嵌套 | 攔截器鏈 | 攔截器鏈 |
| 性能 | 直接調用,最快 | 反射調用,較慢 | FastClass 機制,較快 |
| 調試難度 | 易(源碼可見) | 難(動態生成) | 難 |
// 簡化版 Spring 邏輯
if (targetClass.hasInterfaces()) {
return new JdkDynamicAopProxy(config); // 默認走 JDK
} else {
return new CglibAopProxy(config); // 無接口走 CGLIB
}
// 可強制使用 CGLIB: @EnableAspectJAutoProxy(proxyTargetClass = true)
理解代理模式從靜態到動態的演進,掌握 JDK/CGLIB 兩大機制差異,是掌握 Spring AOP、中間件擴展、RPC 框架的基石。