欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

Java結(jié)構(gòu)型模式之代理模式詳解

 更新時(shí)間:2023年02月17日 15:12:26   作者:非凡的小笨魚  
這篇文章主要介紹了Java結(jié)構(gòu)型模式之代理模式,代理模式是常用的java設(shè)計(jì)模式,他的特征是代理類與委托類有同樣的接口,代理類主要負(fù)責(zé)為委托類預(yù)處理消息、過(guò)濾消息、把消息轉(zhuǎn)發(fā)給委托類,以及事后處理消息等

一.介紹

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

二.UML類圖

三.代理模式分類

Java中的代理按照代理類生成時(shí)機(jī)不同分為靜態(tài)代理和動(dòng)態(tài)代理,靜態(tài)代理的代理類在編譯器就生成,而動(dòng)態(tài)代理的代理類在Java運(yùn)行時(shí)動(dòng)態(tài)生成。動(dòng)態(tài)代理又分為JDK代理和CGLib代理。

四.靜態(tài)代理

業(yè)務(wù)代碼

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

測(cè)試代碼

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

五.靜態(tài)代理的優(yōu)缺點(diǎn)

優(yōu)點(diǎn)

  • 符合開閉原則
  • 功能增強(qiáng)無(wú)需改動(dòng)原業(yè)務(wù)代碼(解耦)

缺點(diǎn)

  • 一個(gè)具體類就要產(chǎn)生一個(gè)代理類,可能會(huì)造成類爆炸

六.動(dòng)態(tài)代理

為了彌補(bǔ)靜態(tài)代理的缺點(diǎn),引入了動(dòng)態(tài)代理

1.JDK動(dòng)態(tài)代理(利用Java提供的代理機(jī)制)

業(yè)務(wù)代碼

/**
 * JDK動(dòng)態(tài)代理
 */
public interface Pay {
    void pay();
}
//真實(shí)類
class Alipay implements Pay {
    @Override
    public void pay() {
        System.out.println("支付寶支付");
    }
}
class PayProxy {
    //組合真實(shí)對(duì)象
    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("執(zhí)行了" + (System.currentTimeMillis() - startTime) + "毫秒");
                return result;
            }
        });
    }
}

測(cè)試代碼

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

我們通過(guò)arthas工具進(jìn)行反編譯,可以找到真正的代理類$Proxy0

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

總結(jié)執(zhí)行流程如下

  1. 測(cè)試代碼里執(zhí)行了pay.pay()
  2. 根據(jù)多態(tài)的特性,執(zhí)行的是代理類($Proxy0)中的pay方法
  3. 代理類($Proxy0)中的pay方法中執(zhí)行了invocationHandler對(duì)象的invoke方法
  4. invocationHandler對(duì)象的invoke方法就是業(yè)務(wù)代碼中傳入的匿名內(nèi)部類中重寫的invoke方法
  5. 在重寫的invoke方法中通過(guò)反射調(diào)用真實(shí)對(duì)象alipay的pay方法

2.CGLib動(dòng)態(tài)代理

JDK動(dòng)態(tài)代理要求必須定義接口,如果沒(méi)有定義接口,就可以使用CGLib動(dòng)態(tài)代理,CGLib為JDK的動(dòng)態(tài)代理提供了很好的補(bǔ)充

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

業(yè)務(wù)代碼

//真實(shí)對(duì)象
class Alipay implements Pay {
    @Override
    public void pay() {
        System.out.println("支付寶支付");
    }
}
class AlipayProxy implements MethodInterceptor {
    //組合真實(shí)對(duì)象
    private Alipay alipay = new Alipay();
    public Alipay getProxy(){
        Enhancer enhancer = new Enhancer();
        enhancer.setSuperclass(Alipay.class);
        //設(shè)置回調(diào)函數(shù)
        enhancer.setCallback(this);
        //返回代理對(duì)象
        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("執(zhí)行了" + (System.currentTimeMillis() - startTime) + "毫秒");
        return result;
    }
}

測(cè)試代碼

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

七.JDK代理與CGLIB代理對(duì)比

  • JDK代理要求必須定義接口,CGLib不用
  • CGLib的原理是動(dòng)態(tài)生成被代理類的子類,所以類和方法都不能定義成final
  • CGLib代理速度>JDK代理速度的場(chǎng)景:JDK1.6之前、JDK1.6與JDK1.7進(jìn)行大量調(diào)用,其余場(chǎng)景JDK代理速度更快(因此在有接口的情況下推薦使用JDK動(dòng)態(tài)代理)

八.代理模式的優(yōu)缺點(diǎn)

優(yōu)點(diǎn)

  • 保護(hù)真實(shí)對(duì)象,使用代理對(duì)象與客戶端交互
  • 符合開閉原則
  • 客戶端與真實(shí)對(duì)象之間解耦

缺點(diǎn)

  • 代理類的創(chuàng)建,增加了系統(tǒng)復(fù)雜度

九.使用場(chǎng)景

1.功能擴(kuò)展:日志、監(jiān)控、事務(wù)

2.控制管理:權(quán)限、限流

3.遠(yuǎn)程代理:FeignClient、RMI

4.動(dòng)態(tài)邏輯:mybatis mapper、jpa

5.延遲加載:虛代理

十.通用的動(dòng)態(tài)代理實(shí)現(xiàn)(拓展)

上文提到靜態(tài)代理是一個(gè)具體類產(chǎn)生一個(gè)代理類,可能會(huì)造成類爆炸,我們現(xiàn)在反觀動(dòng)態(tài)代理則是一個(gè)接口產(chǎn)生一個(gè)代理類,也可能會(huì)造成類爆炸,所以這里給出一個(gè)較為通用的實(shí)現(xiàn)

業(yè)務(wù)代碼

//記錄執(zhí)行的時(shí)間的通用類
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("執(zhí)行了" + (System.currentTimeMillis()-startTime) + "毫秒");
        return result;
    }
}

測(cè)試代碼

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

Spring AOP是代理模式的典型應(yīng)用

到此這篇關(guān)于Java結(jié)構(gòu)型模式之代理模式詳解的文章就介紹到這了,更多相關(guān)Java代理模式內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • Java replaceAll()方法報(bào)錯(cuò)Illegal group reference的解決辦法

    Java replaceAll()方法報(bào)錯(cuò)Illegal group reference的解決辦法

    這篇文章主要給大家介紹了關(guān)于Java replaceAll()方法報(bào)錯(cuò)Illegal group reference的解決辦法,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧
    2020-09-09
  • Micronaut框架的簡(jiǎn)單使用介紹

    Micronaut框架的簡(jiǎn)單使用介紹

    這篇文章主要介紹了Micronaut框架的簡(jiǎn)單使用介紹,幫助大家更好的理解和學(xué)習(xí)使用Micronaut,感興趣的朋友可以了解下
    2021-04-04
  • 使用idea生成springboot程序的docker鏡像的操作指南

    使用idea生成springboot程序的docker鏡像的操作指南

    這篇文章給大家詳細(xì)的介紹了使用idea生成springboot程序的docker鏡像的操作指南,文中通過(guò)圖文結(jié)合給大家講解的非常詳細(xì),具有一定的參考價(jià)值,需要的朋友可以參考下
    2023-12-12
  • Java自定義函數(shù)調(diào)用方法解析

    Java自定義函數(shù)調(diào)用方法解析

    這篇文章主要介紹了java自定義函數(shù)調(diào)用方法解析,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下
    2019-11-11
  • springboot中JSONObject遍歷并替換部分json值

    springboot中JSONObject遍歷并替換部分json值

    這篇文章主要介紹了springboot中JSONObject遍歷并替換部分json值,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧
    2020-11-11
  • springboot整合nacos,如何讀取nacos配置文件

    springboot整合nacos,如何讀取nacos配置文件

    這篇文章主要介紹了springboot整合nacos,如何讀取nacos配置文件問(wèn)題,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2022-11-11
  • 解決Springboot項(xiàng)目報(bào)錯(cuò):java:錯(cuò)誤:不支持發(fā)行版本?17

    解決Springboot項(xiàng)目報(bào)錯(cuò):java:錯(cuò)誤:不支持發(fā)行版本?17

    這篇文章主要給大家介紹了關(guān)于解決Springboot項(xiàng)目報(bào)錯(cuò):java:錯(cuò)誤:不支持發(fā)行版本17的相關(guān)資料,這個(gè)錯(cuò)誤意味著你的Spring Boot項(xiàng)目正在使用Java 17這個(gè)版本,但是你的項(xiàng)目中未配置正確的Java版本,需要的朋友可以參考下
    2023-08-08
  • Springboot應(yīng)用gradle?Plugin示例詳解

    Springboot應(yīng)用gradle?Plugin示例詳解

    這篇文章主要介紹了Springboot應(yīng)用gradle?Plugin詳解,本文給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下
    2023-04-04
  • 詳解Java語(yǔ)言中一個(gè)字符占幾個(gè)字節(jié)?

    詳解Java語(yǔ)言中一個(gè)字符占幾個(gè)字節(jié)?

    這篇文章主要介紹了Java語(yǔ)言中一個(gè)字符占幾個(gè)字節(jié),文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧
    2019-04-04
  • java 根據(jù)坐標(biāo)截取圖片實(shí)例代碼

    java 根據(jù)坐標(biāo)截取圖片實(shí)例代碼

    這篇文章主要介紹了java 根據(jù)坐標(biāo)截取圖片實(shí)例代碼的相關(guān)資料,需要的朋友可以參考下
    2017-03-03

最新評(píng)論