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

JDK 動態代理實戰教程:從核心原理到 AOP 應用場景全解析

     編輯:Java 程式設計入門

核心原理

JDK 動態代理基於 反射機制(java.lang.reflect),運行時動態生成實現目標接口的代理類。核心角色:

  • 接口:定義服務契約(如 Singer);
  • 目標對象:接口實現類(如 MySinger);
  • 調用處理器:實現 InvocationHandler,攔截方法調用(如 Agent);
  • 代理對象:Proxy.newProxyInstance() 生成,委託給 InvocationHandler。

完整代碼示例

// 1. 服務接口
public interface Singer {
    void sing();
    String s();
}

// 2. 目標實現
public class MySinger implements Singer {
    public void sing() { System.err.println("唱歌。。。。"); }
    public String s() { return "Jay Chou"; }
}

// 3. 代理處理器(經紀人)
public class Agent implements InvocationHandler {
    private Object target;

    public Object bind(Object target) {
        this.target = target;
        return Proxy.newProxyInstance(
            target.getClass().getClassLoader(),
            target.getClass().getInterfaces(),
            this
        );
    }

    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        System.out.println("開始事務");
        System.out.println("判斷權限");
        Object result = method.invoke(target, args); // 執行目標方法
        System.out.println("結束事務");
        return result;
    }
}

// 4. 測試
public class Test {
    public static void main(String[] args) {
        Agent agent = new Agent();
        Singer proxy = (Singer) agent.bind(new MySinger());
        proxy.sing();
        System.out.println(proxy.s());
    }
}

關鍵優勢

  1. 一個代理類服務多個目標:只要實現同一接口,Agent 可代理任意 Singer 實現;
  2. 關注點分離:事務、權限、日志、監控等橫切邏輯集中在 invoke,業務代碼純淨;
  3. 運行時動態性:無需編譯期生成代理類,適配插件化、熱更新場景。

局限性與補充

  • 只能代理接口:目標類必須實現一個或多個接口,無法代理普通類;
  • 性能開銷:反射調用比直接調用慢,高頻熱點路徑需謹慎;
  • CGLIB 補位:針對無接口類,通過繼承字節碼生成子類代理,Spring AOP 默認混合使用。

Spring AOP 中的應用

@Aspect
@Component
public class TxAspect {
    @Around("execution(* com.service.*.*(..))")
    public Object txAdvice(ProceedingJoinPoint pjp) throws Throwable {
        // 開啟事務
        Object ret = pjp.proceed(); // 相當於 method.invoke()
        // 提交/回滾事務
        return ret;
    }
}

Spring 將 InvocationHandler 抽象為 MethodInterceptor,配合切點表達式實現聲明式事務,本質同樣是動態代理模式。

最佳實踐建議

  1. 接口設計盡量精簡,單一職責;
  2. 代理邏輯保持輕量,避免在 invoke 中做耗時操作;
  3. 結合 Proxy.newProxyInstance(classLoader, interfaces, handler) 參數含義理解類加載器隔離問題;
  4. 調試時可通過 -Dsun.misc.ProxyGenerator.saveGeneratedFiles=true 導出生成的代理類源碼分析。
  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved