// 1. 公共接口
public interface Service {
void add();
}
// 2. 被代理類
public class ServiceImpl implements Service {
@Override
public void add() {
System.out.println("執行添加用戶業務...");
}
}
// 3. 代理類(手寫,編譯期就存在 .class)
public class ServiceProxy implements Service {
private final Service target;
public ServiceProxy(Service target) {
this.target = target;
}
@Override
public void add() {
System.out.println("[代理] 開啟事務");
target.add();
System.out.println("[代理] 提交事務");
}
}
// 4. 測試
public class StaticProxyTest {
public static void main(String[] args) {
Service target = new ServiceImpl();
Service proxy = new ServiceProxy(target);
proxy.add();
}
}
java.lang.reflect.Proxy:代理類生成工廠java.lang.reflect.InvocationHandler:統一調用分發器// 1. 實現 InvocationHandler
public class ServiceInvocationHandler implements InvocationHandler {
private final Object target;
public ServiceInvocationHandler(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;
}
}
// 2. 使用 Proxy.newProxyInstance 生成代理實例
public class DynamicProxyTest {
public static void main(String[] args) {
Service target = new ServiceImpl();
InvocationHandler handler = new ServiceInvocationHandler(target);
// 關鍵三參數:類加載器、實現的接口數組、處理器
Service proxy = (Service) Proxy.newProxyInstance(
target.getClass().getClassLoader(),
target.getClass().getInterfaces(),
handler
);
proxy.add(); // 觸發 invoke()
}
}
public static Object newProxyInstance(ClassLoader loader,
Class>[] interfaces,
InvocationHandler h) {
// 1. 參數校驗
Objects.requireNonNull(h);
final Class>[] intfs = interfaces.clone();
// ... 安全檢查 ...
// 2. 獲取/生成代理類 Class 對象(緩存機制)
Class> cl = getProxyClass0(loader, intfs);
// 3. 獲取構造器(唯一參數為 InvocationHandler)
final Constructor> cons = cl.getConstructor(constructorParams);
// 4. 實例化代理對象
return cons.newInstance(new Object[]{h});
}
proxyClassCache 以 (ClassLoader, Interfaces[]) 為 Key,避免重複生成com.sun.proxy.$Proxy0、$Proxy1...extends Proxy implements Interface1, Interface2...public final void add() throws {
try {
super.h.invoke(this, m0, null); // m0 為 Method 對象
} catch (RuntimeException | Error e) { throw e; }
catch (Throwable e) { throw new UndeclaredThrowableException(e); }
}
Java 單繼承機制導致:動態生成的類已繼承 Proxy,無法再繼承業務類。解決方案:CGLIB / ByteBuddy(子類繼承方式,字節碼增強)。
final/private/static 方法無法被重寫,代理類中不會生成對應方法,調用直接走目標對象或拋異常。
Java 8 接口默認方法,動態代理不會自動調用默認實現,除非在 invoke 中手動處理:
if (method.isDefault()) {
// 手動調用默認方法 (Java 8+)
MethodHandle mh = MethodHandles.lookup()
.findSpecial(target.getClass(), method.getName(),
MethodType.methodType(method.getReturnType(), method.getParameterTypes()), target.getClass());
return mh.bindTo(target).invokeWithArguments(args);
}
原理:動態拼接 Java 源碼 → JavaCompiler 編譯 → ClassLoader 加載 → 反射實例化。生產環境絕不可用,僅供理解原理。
| 維度 | 靜態代理 | JDK 動態代理 | CGLIB 動態代理 |
|---|---|---|---|
| 生成時機 | 編譯期 | 運行時 | 運行時 |
| 目標類型 | 接口/類 | 只能接口 | 類/接口 |
| 性能 | 最高(直接調用) | 反射調用,略低 | FastClass 機制,較快 |
| 適用場景 | 固定、少量增強 | 接口多、通用攔截 | 無接口、第三方類增強 |
proxy-target-class=true 全用 CGLIB)ProxyGenerator 緩存,避免類加載器洩漏