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

Java 動態代理模式深度解析:InvocationHandler 與 Proxy 實戰應用

     編輯:Java 相關知識

動態代理核心架構

Java java.lang.reflect 套件提供動態代理能力:運行時生成實現指定介面的代理類,將方法呼叫轉發給指定處理器。核心三角色:

  • Subject 介面:定義業務契約
  • Proxy (代理):JVM 自動生成,實現 Subject 介面
  • InvocationHandler:攔截代理上所有方法呼叫,決定如何轉發給 RealSubject

動態代理 UML 結構圖

核心 API 簽名


// InvocationHandler 唯一必須實作的方法
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable;

// Proxy 建立代理實例的靜態工廠方法
public static Object newProxyInstance(ClassLoader loader, 
                                      Class[] interfaces, 
                                      InvocationHandler h);

關鍵: 代理類非開發者撰寫,業務邏輯集中於 InvocationHandler.invoke() 中。

實戰案例:權限控制的 Person Bean

場景

  • 本人:可查看/修改姓名、性別;不可修改評分
  • 他人:可查看姓名、性別;可修改評分;不可修改姓名、性別

1. 定義介面


public interface Person {
    String getName(); String getGender();
    void setName(String name); void setGender(String gender);
    void setRate(int rate); int getRate();
}

2. 實作類


public class PersonImpl implements Person {
    private String name, gender, interests;
    private int rate;
    // 標準 getter/setter 略
}

3. 本人權限處理器


public class OwnerInvocationHandler implements InvocationHandler {
    private Person target;
    public OwnerInvocationHandler(Person target) { this.target = target; }
    
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        String methodName = method.getName();
        if (methodName.startsWith("get")) {
            return method.invoke(target, args);  // 所有 get 允許
        } else if (methodName.equals("setRate")) {
            throw new IllegalAccessException("Access deny");  // 禁止 setRate
        } else if (methodName.startsWith("set")) {
            return method.invoke(target, args);  // 其他 set 允許
        }
        return null;
    }
}

4. 他人權限處理器


public class NonOwnerInvocationHandler implements InvocationHandler {
    private Person target;
    public NonOwnerInvocationHandler(Person target) { this.target = target; }
    
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        String methodName = method.getName();
        if (methodName.startsWith("get") || methodName.equals("setRate")) {
            return method.invoke(target, args);  // get + setRate 允許
        }
        System.out.println("non method invoke: " + methodName);
        return null;  // 其他 set 拒絕
    }
}

5. 代理工廠與測試


public class MyDynamicProxy {
    public Person getOwnerProxy(Person person) {
        return (Person) Proxy.newProxyInstance(
            person.getClass().getClassLoader(),
            person.getClass().getInterfaces(),
            new OwnerInvocationHandler(person));
    }
    public Person getNonOwnerProxy(Person person) {
        return (Person) Proxy.newProxyInstance(
            person.getClass().getClassLoader(),
            person.getClass().getInterfaces(),
            new NonOwnerInvocationHandler(person));
    }
    
    public static void main(String[] args) {
        MyDynamicProxy factory = new MyDynamicProxy();
        
        // 本人代理測試
        Person p1 = new PersonImpl(); p1.setName("Remy"); p1.setGender("Girl"); p1.setRate(1);
        Person ownerProxy = factory.getOwnerProxy(p1);
        System.out.println(ownerProxy.getName());  // Remy
        try { ownerProxy.setRate(2); } 
        catch (Exception e) { System.out.println("can not setRate"); }  // 攔截
        
        // 他人代理測試
        Person p2 = new PersonImpl(); p2.setName("Remy"); p2.setGender("Girl"); p2.setRate(1);
        Person nonOwnerProxy = factory.getNonOwnerProxy(p2);
        System.out.println(nonOwnerProxy.getName());  // Remy
        nonOwnerProxy.setRate(2);  // 允許
        System.out.println(nonOwnerProxy.getRate());  // 2
    }
}

輸出結果


Remy
can not setRate
Remy
2

進階應用場景

  • AOP 切面:日誌、事務、安全檢查、效能監控
  • 遠程代理:RMI、Web Service 客戶端存根
  • 虛擬代理:延遲載入大型物件 (如圖片、報表)
  • 保護代理:如本例權限控制

結語

Java 動態代理以 InvocationHandler 集中處理方法攔截邏輯,配合 Proxy.newProxyInstance() 運行時生成代理類,實現非侵入式的橫切關注點分離。本例展示權限控制經典應用,掌握「介面 + 實作 + 多種 Handler + Proxy 工廠」模式,即可靈活應用於 AOP、遠程調用、延遲載入等場景。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved