JDK 動態代理基於接口,通過 Proxy.newProxyInstance 生成實現目標接口的代理類,將方法調用委派給 InvocationHandler。本文通過反射剖析生成類結構,演示三種代理實例創建方式,並實現方法耗時統計切面。
Class<?> proxyClass = Proxy.getProxyClass(Collection.class.getClassLoader(), Collection.class);
System.out.println(proxyClass); // class $Proxy0
// 構造器
for (Constructor<?> c : proxyClass.getConstructors()) {
// 唯一構造器:public $Proxy0(InvocationHandler h)
}
// 方法
for (Method m : proxyClass.getMethods()) {
// 包含 Collection 所有方法 + Object 的 toString/hashCode/equals
}
// 1. 構造器 + 實現類
Constructor<?> ctor = proxyClass.getConstructor(InvocationHandler.class);
Collection p1 = (Collection) ctor.newInstance(new MyHandler());
// 2. 構造器 + 匿名內部類
Collection p2 = (Collection) ctor.newInstance(new InvocationHandler() {
public Object invoke(Object proxy, Method method, Object[] args) { return null; }
});
// 3. Proxy.newProxyInstance 一步到位(推薦)
Collection p3 = (Collection) Proxy.newProxyInstance(
Collection.class.getClassLoader(),
new Class[]{Collection.class},
new InvocationHandler() {
List<Object> target = new ArrayList<>(); // 持有真實目標
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
long start = System.currentTimeMillis();
Object ret = method.invoke(target, args); // 轉發調用
System.out.println(method.getName() + " 耗時 " + (System.currentTimeMillis() - start) + "ms");
return ret;
}
}
);
p3.add("ljl"); p3.add("wiseq"); // 觸發切面邏輯
add(ljl) add 耗時 0ms add(wiseq) add 耗時 0ms size() size 耗時 0ms 集合元素的個數=2 $Proxy0 // 代理類名,非 ArrayList
Proxy,實現目標接口,持有 InvocationHandler 引用。handler.invoke(proxy, method, args)。Object 的 toString/hashCode/equals 也委派給 handler,但 getClass() 返回代理類自身 Class 對象。$Proxy0 為 final 類,不可再被繼承。上述硬編碼方式實戰無意義,實際開發需抽象:
MethodInterceptor。