1. 程式人生 > 實用技巧 >JavaEE - 15反射機制2

JavaEE - 15反射機制2

JavaEE - 15動態代理2

(7)反射的應用:動態代理

(7.1)代理設計模式原理

  • 使用一個代理將物件包裝起來,然後用該代理物件取代原始物件。任何對原始物件的呼叫都要通過代理。
    • 代理物件決定是否以及何時將方法呼叫轉到原始物件上。
  • 靜態代理,特徵是代理類和目標物件的類都是在編譯期確定下來的,不利於程式擴充套件。
    • 每個代理類只能為一個介面服務,這樣一來就比如產生過多的代理。最好可以通過一個代理類完成全部的代理功能。
  • 動態代理是指客戶通過代理類來呼叫其他物件的方法,並且是在程式執行時根據需要動態建立目標類的代理物件。
  • 動態代理使用場合
    • 除錯
    • 遠端方法呼叫
  • 動態代理相比於靜態代理的優點
    • 抽象角色中(介面)宣告的所有方法都被轉移到呼叫處理器一個集中的方法中處理,這樣,我們可以更加靈活和統一的處理眾多的方法。

(7.2)靜態代理

//--介面
public interface ClothFactory {
    void productCloth();
}
// 代理類--------------------
public class ProxyClothFactory implements ClothFactory {
    // 用被代理類物件進行例項化
    private ClothFactory factory;
    public ProxyClothFactory(ClothFactory factory){
        
this.factory = factory; } @Override public void productCloth() { System.out.println("代理工廠做準備工作"); factory.productCloth(); System.out.println("代理工廠做收尾工作"); } }
// 被代理類---------------------- public class NikeClothFactory implements ClothFactory{ @Override
public void productCloth() { System.out.println("Nike工廠生產Nike運動服"); } }
// 測試---------------------- public class ProxyTest { public static void main(String[] args) { NikeClothFactory nikeClothFactory = new NikeClothFactory(); ProxyClothFactory factory = new ProxyClothFactory(nikeClothFactory); factory.productCloth(); } }

(7.3)動態代理

  • 要想實現動態代理,需要解決的問題
    • 一是: 如何根據載入到記憶體中的被代理類,動態的建立一個代理類及其物件。
    • 二是: 當通過代理類的物件呼叫方法時,如何動態的去呼叫被代理類中的同名方法。

介面及被代理類

public interface Human {
    String getBelief();
    void eat(String food);
}
//被代理類 -----------
public class SuperMan implements Human {
    @Override
    public String getBelief() {
        return "I can fly";
    }

    @Override
    public void eat(String food) {
        System.out.println("吃"+food);
    }
}

MyInvocationHandler

public class MyInvocationHandler implements InvocationHandler {
    private Object obj;
    public void bind(Object obj) {
        this.obj = obj;
    }

    // 當我們通過代理類的物件,呼叫方法a時,就會自動的呼叫如下的方法: invoke()
// 將被代理要執行的方法a 的功能宣告在invoke()中。 @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { // method: 代理類物件呼叫的方法,此方法也是被代理類要呼叫的方法 // obj: 被代理類的物件
Object returnValue = method.invoke(obj, args); return returnValue; } }

ProxyFactory代理工廠

public class ProxyFactory {
    // 呼叫此方法,返回一個代理類的物件,解決問題1
    public static Object getProxyInstance(Object obj){ //obj: 被代理類的物件
        MyInvocationHandler handler = new MyInvocationHandler();
        handler.bind(obj);
        return Proxy.newProxyInstance(obj.getClass().getClassLoader(), obj.getClass().getInterfaces(), handler);
    }
}

測試

public class ProxyTest {
    public static void main(String[] args){
        SuperMan superMan = new SuperMan();
        // proxyInstance: 代理類的物件
        Human proxyInstance = (Human) ProxyFactory.getProxyInstance(superMan);
        // 當通過代理類物件呼叫方法時,會自動呼叫被代理類中的同名的方法
        String belief = proxyInstance.getBelief();
        System.out.println(belief);
        proxyInstance.eat("四川麻辣燙");

        System.out.println("-------------------------");
        NikeClothFactory nikeClothFactory = new NikeClothFactory();
        ClothFactory clothFactory = (ClothFactory) ProxyFactory.getProxyInstance(nikeClothFactory);
        clothFactory.productCloth();
    }
}

(7.4)動態代理與AOP(Aspect Orient Programming)

  • 程式碼段1、程式碼段2、程式碼段3都同時呼叫了特定方法A。
  • 理想效果:程式碼段1、2、3既可以執行方法A,又無須在程式中以硬編碼的方式直接呼叫方法A。
  • AOP代理方法:
    • 動態代理增加的通用方法1
    • 回撥目標物件的方法
    • 動態代理增加的通用方法2

通用方法類HumanUtil

public class HumanUtil {
    public void method1(){
        System.out.println("========通用方法1==========");
    }
    public void method2(){
        System.out.println("========通用方法2==========");
    }
}

MyInvocationHandler方法改進

    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        // method: 代理類物件呼叫的方法,此方法也是被代理類要呼叫的方法
        // obj: 被代理類的物件
        HumanUtil humanUtil = new HumanUtil();
        humanUtil.method1();
        Object returnValue = method.invoke(obj, args);
        humanUtil.method2();
        return returnValue;
    }

執行結果:

========通用方法1==========
========通用方法2==========
I can fly
========通用方法1==========
吃四川麻辣燙
========通用方法2==========