首頁 > 軟體

Java動態代理的範例詳解

2022-02-23 19:00:03

定義

動態代理指的是,代理類和目標類的關係在程式執行的時候確定的,客戶通過代理類來呼叫目標物件的方法,是在程式執行時根據需要動態的建立目標類的代理物件。

分類

jdk動態代理

cglib動態代理

案例

需求

蘋果公司通過蘋果代理商來賣手機

方案一:jdk動態代理

定義抽象介面

/**
 * 售賣手機的介面(代理模式——抽象角色)
 * @author:liyajie
 * @createTime:2022/2/22 14:42
 * @version:1.0
 */
public interface IPhone {

    /**
     * 出售手機
     * @author: liyajie
     * @date: 2022/2/22 14:44
     * @param
     * @return void
     * @exception:
     * @update:
     * @updatePerson:
     **/
    void sellPhone();
}

定義目標類實現介面,重寫介面方法

/**
 * 蘋果公司(代理模式——目標角色)
 * @author:liyajie
 * @createTime:2022/2/22 14:46
 * @version:1.0
 */
public class TargetPhone implements IPhone {
    @Override
    public void sellPhone() {
        System.out.println("蘋果公司正在出售手機");
    }
}

定義代理類

/**
 * 代理商(代理模式——代理角色)
 * @author:liyajie
 * @createTime:2022/2/22 14:50
 * @version:1.0
 */
public class ProxyPhone {

    private Object target;

    public ProxyPhone(Object target){
        this.target = target;
    }

    public Object getProxyInstance() {
        return Proxy.newProxyInstance(target.getClass().getClassLoader(),
                target.getClass().getInterfaces(),
                new InvocationHandler() {
                    @Override
                    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
                        System.out.println("JDK動態代理開始之前,新增業務邏輯XXX");
                        //使用反射機制來呼叫目標物件的方法:解決了問題二
                        Object invoke = method.invoke(target, args);
                        System.out.println("JDK動態代理結束之後,新增業務邏輯XXX");
                        return invoke;
                    }
                });
    }
}

定義測試類

/**
 * 測試類
 * @author:liyajie
 * @createTime:2022/2/23 15:15
 * @version:1.0
 */
public class Test {
    public static void main(String[] args) {
        // 建立目標類
        TargetPhone targetPhone = new TargetPhone();
        // 建立代理類
        IPhone iPhone = (IPhone) new ProxyPhone(targetPhone).getProxyInstance();
        System.out.println(iPhone.getClass());
        // 通過代理類呼叫目標方法
        iPhone.sellPhone();
    }
}

檢視測試結果

方案二:cglib動態代理

定義目標類

/**
 * 蘋果公司(代理模式——目標角色)
 * @author:liyajie
 * @createTime:2022/2/22 14:46
 * @version:1.0
 */
public class TargetPhone {

    public void sellPhone() {
        System.out.println("蘋果公司正在出售手機");
    }
}

定義代理工廠,用來獲取代理類

/**
 * 代理工廠
 * @author:liyajie
 * @createTime:2022/2/23 15:32
 * @version:1.0
 */
public class ProxyFactory implements MethodInterceptor {

    private Object target;

    public ProxyFactory(Object target){
        this.target = target;
    }

    public Object getProxyInstance(){
        // 建立一個工具類
        Enhancer enhancer = new Enhancer();
        // 設定父類別
        enhancer.setSuperclass(target.getClass());
        // 設定回撥函數
        enhancer.setCallback(this);
        // 建立子類物件,即代理物件
        return enhancer.create();
    }

    @Override
    public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
        System.out.println("cglib動態代理開始之前,新增業務邏輯xxxx");
        Object invoke = method.invoke(target, objects);
        System.out.println("cglib動態代理之後,新增業務邏輯");
        return invoke;
    }
}

定義測試類

/**
 * 測試類
 * @author:liyajie
 * @createTime:2022/2/23 15:44
 * @version:1.0
 */
public class Test {
    public static void main(String[] args) {
        // 建立目標物件
        TargetPhone targetPhone = new TargetPhone();
        // 獲取代理物件
        TargetPhone proxyInstance = (TargetPhone)new ProxyFactory(targetPhone).getProxyInstance();
        // 通過代理物件呼叫具體的方法
        proxyInstance.sellPhone();
    }
}

檢視測試結果

分析

首先可以看到不管是jdk動態代理,還是cglib動態代理,實現的效果和靜態代理是一模一樣的,都實現了功能的擴充套件。但是兩種動態代理還是有些不同的,其中jdk動態代理需要目標物件實現介面,但是cglib動態代理不需要,因為他是在記憶體中構建一個子類物件,從而實現對目標物件的功能擴充套件。

總結

通過案例,我們瞭解了代理模式的幾種實現方式,下面我們總結下該模式:

優勢:

  • 代理模式在使用者端和目標物件之間起到了一箇中介和保護的作用
  • 代理物件可以對目標物件進行功能的擴充套件和業務的擴充套件,增強目標物件
  • 代理模式可以將使用者端和目標物件分離,在一定程度上降低了系統的耦合度

劣勢:

  • 請求需要經過代理物件,會導致處理速度變慢
  • 因為會有大量的代理物件產生,會增加系統的複雜度

到此這篇關於Java動態代理的範例詳解的文章就介紹到這了,更多相關Java 動態代理內容請搜尋it145.com以前的文章或繼續瀏覽下面的相關文章希望大家以後多多支援it145.com!


IT145.com E-mail:sddin#qq.com