Java動態代理的示例詳解

定義

動態代理指的是,代理類和目標類的關系在程序運行的時候確定的,客戶通過代理類來調用目標對象的方法,是在程序運行時根據需要動態的創建目標類的代理對象。

分類

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 動態代理內容請搜索WalkonNet以前的文章或繼續瀏覽下面的相關文章希望大傢以後多多支持WalkonNet!

推薦閱讀: