91超碰碰碰碰久久久久久综合_超碰av人澡人澡人澡人澡人掠_国产黄大片在线观看画质优化_txt小说免费全本

溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務條款》

Java結構型模式之代理模式怎么實現

發布時間:2023-02-20 09:47:38 來源:億速云 閱讀:80 作者:iii 欄目:開發技術

今天小編給大家分享一下Java結構型模式之代理模式怎么實現的相關知識點,內容詳細,邏輯清晰,相信大部分人都還太了解這方面的知識,所以分享這篇文章給大家參考一下,希望大家閱讀完這篇文章后有所收獲,下面我們一起來了解一下吧。

一.介紹

在代理模式(Proxy Pattern)屬于結構型模式。在代理模式中,我們對一個對象提供一個代理對象,使用代理對象控制原對象的引用,目的是為了透明的控制對象訪問

二.UML類圖

Java結構型模式之代理模式怎么實現

三.代理模式分類

Java中的代理按照代理類生成時機不同分為靜態代理和動態代理,靜態代理的代理類在編譯器就生成,而動態代理的代理類在Java運行時動態生成。動態代理又分為JDK代理和CGLib代理。

四.靜態代理

業務代碼

/**
 * 靜態代理
 */
public interface Pay {
    void pay();
}
//真實類
class Alipay implements Pay {
    @Override
    public void pay() {
        System.out.println("支付寶支付");
    }
}
//代理類
class AlipayProxy implements Pay{
    //組合真實對象
    private final Alipay alipay = new Alipay();
    @Override
    public void pay() {
        long startTime = System.currentTimeMillis();
        alipay.pay();
        System.out.println("執行了" + (System.currentTimeMillis()-startTime) + "毫秒"); //支付寶支付 執行了0毫秒
    }
}

測試代碼

public class Client {
    public static void main(String[] args) {
        new AlipayProxy().pay();
    }
}

五.靜態代理的優缺點

優點

  • 符合開閉原則

  • 功能增強無需改動原業務代碼(解耦)

缺點

  • 一個具體類就要產生一個代理類,可能會造成類爆炸

六.動態代理

為了彌補靜態代理的缺點,引入了動態代理

1.JDK動態代理(利用Java提供的代理機制)

業務代碼

/**
 * JDK動態代理
 */
public interface Pay {
    void pay();
}
//真實類
class Alipay implements Pay {
    @Override
    public void pay() {
        System.out.println("支付寶支付");
    }
}
class PayProxy {
    //組合真實對象
    private Pay pay;
    public PayProxy(Pay pay) {
        this.pay = pay;
    }
    public Pay getProxy() {
        return (Pay) Proxy.newProxyInstance(getClass().getClassLoader(), pay.getClass().getInterfaces(), new InvocationHandler() {
            @Override
            public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
                long startTime = System.currentTimeMillis();
                Object result = method.invoke(pay, args);
                System.out.println("執行了" + (System.currentTimeMillis() - startTime) + "毫秒");
                return result;
            }
        });
    }
}

測試代碼

public class Client {
    public static void main(String[] args) {
        PayProxy payProxy = new PayProxy(new Alipay());
        Pay pay = payProxy.getProxy();
        pay.pay(); //支付寶支付 執行了0毫秒
    }
}

我們通過arthas工具進行反編譯,可以找到真正的代理類$Proxy0

//代理對象
public final class $Proxy0 extends Proxy implements Pay {
    private static Method m3;
    public $Proxy0(InvocationHandler invocationHandler) {
        super(invocationHandler);
    }
    static {
        // 通過反射獲取名叫pay的menthod
        m3 = Class.forName("com.designpattern.structure.proxy.v2.Pay").getMethod("pay", new Class[0]);
        return;
    }
    public final void pay() {
        // h是invocationHandler對象
        this.h.invoke(this, m3, null);
        return;
    }
}

總結執行流程如下

  1. 測試代碼里執行了pay.pay()

  2. 根據多態的特性,執行的是代理類($Proxy0)中的pay方法

  3. 代理類($Proxy0)中的pay方法中執行了invocationHandler對象的invoke方法

  4. invocationHandler對象的invoke方法就是業務代碼中傳入的匿名內部類中重寫的invoke方法

  5. 在重寫的invoke方法中通過反射調用真實對象alipay的pay方法

2.CGLib動態代理

JDK動態代理要求必須定義接口,如果沒有定義接口,就可以使用CGLib動態代理,CGLib為JDK的動態代理提供了很好的補充

首先引入cglib-3.3.0.jar與asm-9.0.jar

業務代碼

//真實對象
class Alipay implements Pay {
    @Override
    public void pay() {
        System.out.println("支付寶支付");
    }
}
class AlipayProxy implements MethodInterceptor {
    //組合真實對象
    private Alipay alipay = new Alipay();
    public Alipay getProxy(){
        Enhancer enhancer = new Enhancer();
        enhancer.setSuperclass(Alipay.class);
        //設置回調函數
        enhancer.setCallback(this);
        //返回代理對象
        return (Alipay) enhancer.create();
    }
    @Override
    public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable {
        long startTime = System.currentTimeMillis();
        Object result = method.invoke(alipay, args);
        System.out.println("執行了" + (System.currentTimeMillis() - startTime) + "毫秒");
        return result;
    }
}

測試代碼

public class Client {
    public static void main(String[] args) {
        Alipay proxy = new AlipayProxy().getProxy();
        proxy.pay(); //支付寶支付 執行了0毫秒
    }
}

七.JDK代理與CGLIB代理對比

  • JDK代理要求必須定義接口,CGLib不用

  • CGLib的原理是動態生成被代理類的子類,所以類和方法都不能定義成final

  • CGLib代理速度>JDK代理速度的場景:JDK1.6之前、JDK1.6與JDK1.7進行大量調用,其余場景JDK代理速度更快(因此在有接口的情況下推薦使用JDK動態代理)

八.代理模式的優缺點

優點

  • 保護真實對象,使用代理對象與客戶端交互

  • 符合開閉原則

  • 客戶端與真實對象之間解耦

缺點

  • 代理類的創建,增加了系統復雜度

九.使用場景

1.功能擴展:日志、監控、事務

2.控制管理:權限、限流

3.遠程代理:FeignClient、RMI

4.動態邏輯:mybatis mapper、jpa

5.延遲加載:虛代理

十.通用的動態代理實現(拓展)

上文提到靜態代理是一個具體類產生一個代理類,可能會造成類爆炸,我們現在反觀動態代理則是一個接口產生一個代理類,也可能會造成類爆炸,所以這里給出一個較為通用的實現

業務代碼

//記錄執行的時間的通用類
public class TimeRecordProxy<T> {
    private final T target;
    public TimeRecordProxy(T target) {
        this.target = target;
    }
    @SuppressWarnings("unchecked")
    public T getProxy() {
        return (T) Proxy.newProxyInstance(this.getClass().getClassLoader(),
                target.getClass().getInterfaces(),
                this::invoke);
    }
    private Object invoke(Object proxy, Method method, Object[] args) throws InvocationTargetException, IllegalAccessException {
        long startTime = System.currentTimeMillis();
        Object result = method.invoke(target, args);
        System.out.println("執行了" + (System.currentTimeMillis()-startTime) + "毫秒");
        return result;
    }
}

測試代碼

public class Client {
    public static void main(String[] args) {
        TimeRecordProxy<Pay> timeRecordProxy = new TimeRecordProxy<>(new Alipay());
        timeRecordProxy.getProxy().pay(); //支付寶支付 執行了0毫秒
    }
}

以上就是“Java結構型模式之代理模式怎么實現”這篇文章的所有內容,感謝各位的閱讀!相信大家閱讀完這篇文章都有很大的收獲,小編每天都會為大家更新不同的知識,如果還想學習更多的知識,請關注億速云行業資訊頻道。

向AI問一下細節

免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。

AI

元江| 鹿邑县| 潞西市| 连城县| 长顺县| 甘谷县| 左贡县| 五华县| 博兴县| 宁波市| 军事| 安乡县| 龙泉市| 会宁县| 黎平县| 宁化县| 水城县| 杭州市| 泌阳县| 苍溪县| 萨迦县| 河西区| 虹口区| 宣城市| 武陟县| 连江县| 金寨县| 青浦区| 大同县| 承德县| 孝义市| 五寨县| 清水县| 乐昌市| 南陵县| 涞源县| 民丰县| 永新县| 沽源县| 攀枝花市| 永嘉县|