動態代理在運行時動態生成代理類,實現對目標對象方法調用的攔截與增強,是 AOP(面向切面編程)的核心實現機制。Spring、MyBatis、Dubbo 等主流框架廣泛應用。
| 維度 | JDK 動態代理 | CGLIB |
|---|---|---|
| 核心原理 | 接口代理:生成實現目標接口的匿名類 | 繼承代理:生成目標類的子類,重寫方法 |
| 前置條件 | 目標類必須實現一個或多個接口 | 目標類不能為 final、方法不能為 final |
| 核心類 | java.lang.reflect.Proxy、InvocationHandler | net.sf.cglib.proxy.Enhancer、MethodInterceptor |
| 性能特點 | 調用通過反射,創建快、調用稍慢 | FastClass 機制索引調用,創建慢、調用快 |
| 適用場景 | 有接口、輕量級代理 | 無接口、高性能調用、第三方類增強 |
public interface UserService {
void addUser();
void removeUser();
void searchUser();
}
public class UserServiceImpl implements UserService {
public void addUser() { System.out.println("add user"); }
public void removeUser() { System.out.println("remove user"); }
public void searchUser() { System.out.println("search user"); }
}
public class TransactionInterceptor implements InvocationHandler {
private Object target; // 目標對象
public void setTarget(Object target) {
this.target = target;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println("【事務】開始事務");
try {
Object result = method.invoke(target, args); // 執行目標方法
System.out.println("【事務】提交事務");
return result;
} catch (Exception e) {
System.out.println("【事務】回滾事務");
throw e;
}
}
}
public class JdkProxyTest {
public static void main(String[] args) {
UserService target = new UserServiceImpl();
TransactionInterceptor interceptor = new TransactionInterceptor();
interceptor.setTarget(target);
// 關鍵:Proxy.newProxyInstance
UserService proxy = (UserService) Proxy.newProxyInstance(
target.getClass().getClassLoader(), // 類加載器
target.getClass().getInterfaces(), // 實現的接口
interceptor // 處理器
);
proxy.addUser(); // 通過代理調用
}
}
【事務】開始事務
add user
【事務】提交事務
public class UserServiceCglibInterceptor implements MethodInterceptor {
@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;
}
}
public class CglibProxyTest {
public static void main(String[] args) {
Enhancer enhancer = new Enhancer();
enhancer.setSuperclass(UserServiceImpl.class); // 目標類
enhancer.setCallback(new UserServiceCglibInterceptor());
UserServiceImpl proxy = (UserServiceImpl) enhancer.create();
proxy.addUser();
}
}
【CGLIB事務】開始事務
add user
【CGLIB事務】提交事務
// Spring 默認策略
@EnableAspectJAutoProxy(proxyTargetClass = false) // 默認 JDK 代理(有接口)
@EnableAspectJAutoProxy(proxyTargetClass = true) // 強制 CGLIB 代理
判斷邏輯:
proxyTargetClass=true → CGLIB 代理proxyTargetClass=true(優先 CGLIB)public final class $Proxy0 extends Proxy implements UserService {
protected $Proxy0(InvocationHandler h) { super(h); }
public void addUser() {
try {
super.h.invoke(this, M_addUser, new Object[0]);
} catch (Error|RuntimeException e) { throw e; }
catch (Throwable e) { throw new UndeclaredThrowableException(e); }
}
// ... 其他接口方法
}
特點:繼承 Proxy、實現目標接口、方法體委託 InvocationHandler.invoke
public class UserServiceImpl$$EnhancerByCGLIB$$123456 extends UserServiceImpl {
private MethodInterceptor CGLIB$CALLBACK_0;
public void addUser() {
MethodInterceptor interceptor = CGLIB$CALLBACK_0;
if (interceptor != null) {
interceptor.intercept(this, M_addUser, new Object[0], P_addUser);
} else {
super.addUser();
}
}
}
特點:繼承目標類、重寫非 final 方法、委託 MethodInterceptor.intercept
| 問題 | 原因 | 解決 |
|---|---|---|
| final 方法不生效 | CGLIB 無法重寫 final 方法 | 避免 final 方法、或使用 JDK 代理 |
| 私有方法不攔截 | 代理無法訪問 private 方法 | 改為 protected/package-private |
| 內部方法調用失效 | this.method() 繞過代理 | AopContext.currentProxy() 或重構 |
| 序列化失敗 | 動態生成類無 serialVersionUID | 實現 Serializable、設置 serialVersionUID |
| 性能問題 | 頻繁創建代理/反射調用開銷 | 緩存代理對象、使用 CGLIB FastClass |
@Transactional 底層即動態代理@Cacheable 方法結果緩存動態代理是 Java 框架開發的基石技術。JDK Proxy 基於接口、標準庫無依賴;CGLIB 基於繼承、功能更強、性能更優。理解兩者原理、適用場景、限制與 Spring 整合策略,對掌握 AOP 本質、排查代理相關疑難雜症、設計擴展性框架具有關鍵價值。