首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> Java 程式設計 >> Java 綜合教學

JDK 動態代理深度實戰:Proxy 生成類結構、InvocationHandler 三種實例化方式與切面計時演示

     編輯:Java 綜合教學

JDK 動態代理深度實戰:Proxy 生成類結構、InvocationHandler 三種實例化方式與切面計時演示

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 類,不可再被繼承。

硬編碼到參數化的演進

上述硬編碼方式實戰無意義,實際開發需抽象:

  1. 目標對象作為參數傳入 handler 構造器。
  2. 切面邏輯(日志、事務、權限)封裝為可複用的 MethodInterceptor。
  3. 通過工廠方法根據配置動態生成代理,即 Spring AOP 核心思想。
  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved