最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

一文搞懂Java常見的三種代理模式(靜態(tài)代理、動(dòng)態(tài)代理和cglib代理)

 更新時(shí)間:2023年08月09日 10:35:25   作者:半畝方塘立身  
Java中常見的三種代理模式是靜態(tài)代理模式、動(dòng)態(tài)代理模式和CGLIB代理模式,本文就來(lái)給大家詳細(xì)的講解一下這三種代理模式,感興趣的小伙伴跟著小編一起來(lái)看看吧

Java靜態(tài)代理

Java中的靜態(tài)代理是一種設(shè)計(jì)模式,它通過創(chuàng)建一個(gè)代理類來(lái)代替原始類,從而控制對(duì)原始類的訪問。代理類和原始類都實(shí)現(xiàn)相同的接口,使得客戶端在使用時(shí)無(wú)需關(guān)心具體的實(shí)現(xiàn)細(xì)節(jié)。靜態(tài)代理在編譯時(shí)就已經(jīng)確定代理類和原始類的關(guān)系,因此稱為靜態(tài)代理。

下面是Java靜態(tài)代理UML類圖:

image.png

示例代碼: 假設(shè)有一個(gè)文件上傳的接口 FileUploader ,其真實(shí)實(shí)現(xiàn)為 RealFileUploader ,我們需要在上傳文件前后記錄日志,這時(shí)就可以使用靜態(tài)代理。

首先,定義抽象接口 FileUploader

public interface FileUploader {
    void upload(String file);
}

然后,實(shí)現(xiàn)真實(shí)上傳 RealFileUploader

public class RealFileUploader implements FileUploader {
    @Override
    public void upload(String file) {
        // 實(shí)際的文件上傳邏輯
        System.out.println("Uploading file: " + file);
    }
}

接下來(lái),實(shí)現(xiàn)代理 ProxyFileUploader

public class ProxyFileUploader implements FileUploader {
    private FileUploader realFileUploader;
    public ProxyFileUploader(FileUploader realFileUploader) {
        this.realFileUploader = realFileUploader;
    }
    @Override
    public void upload(String file) {
        // 額外的處理,比如記錄日志
        System.out.println("Before uploading: " + file);
        // 調(diào)用真實(shí)主題的上傳方法
        realFileUploader.upload(file);
        // 額外的處理,比如記錄日志
        System.out.println("After uploading: " + file);
    }
}

在使用時(shí),我們可以這樣創(chuàng)建代理類并進(jìn)行文件上傳:

public class Main {
    public static void main(String[] args) {
        // 創(chuàng)建真實(shí)主題
        FileUploader realFileUploader = new RealFileUploader();
        // 創(chuàng)建代理主題,并將真實(shí)主題傳入
        FileUploader proxyFileUploader = new ProxyFileUploader(realFileUploader);
        // 通過代理主題進(jìn)行文件上傳
        proxyFileUploader.upload("example.txt");
    }
}

運(yùn)行上述代碼,輸出將會(huì)是:

Before uploading: example.txt
Uploading file: example.txt
After uploading: example.txt

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

Java動(dòng)態(tài)代理是一種在運(yùn)行時(shí)創(chuàng)建代理類的機(jī)制,它允許在不提前知道代理類的具體類型的情況下,動(dòng)態(tài)地創(chuàng)建一個(gè)代理對(duì)象來(lái)代替原始類。相比于靜態(tài)代理,動(dòng)態(tài)代理更加靈活,可以代理任意的接口類型,不需要為每個(gè)被代理的類編寫專門的代理類,而是通過Java的反射機(jī)制在運(yùn)行時(shí)動(dòng)態(tài)生成代理類。動(dòng)態(tài)代理主要使用 java.lang.reflect.Proxy 類和 java.lang.reflect.InvocationHandler 接口來(lái)實(shí)現(xiàn)。動(dòng)態(tài)代理又被稱為JDK代理或接口代理。

下面看下動(dòng)態(tài)代理的UML圖:

java動(dòng)態(tài)代理 (1).png

示例代碼: 與前面的靜態(tài)代理示例相同,我們?nèi)匀皇褂梦募蟼鞯慕涌?FileUploader ,其真實(shí)實(shí)現(xiàn)為 RealFileUploader 。接下來(lái),我們將通過動(dòng)態(tài)代理在上傳文件前后記錄日志。

首先,定義抽象主題接口 FileUploader 和實(shí)現(xiàn)真實(shí)主題 RealFileUploader ,與之前相同,不再重復(fù)。

然后,實(shí)現(xiàn) InvocationHandler 接口,創(chuàng)建動(dòng)態(tài)代理的處理器類 DynamicProxyHandler

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
public class DynamicProxyHandler implements InvocationHandler {
    private Object realObject;
    public DynamicProxyHandler(Object realObject) {
        this.realObject = realObject;
    }
    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        // 額外的處理,比如記錄日志
        System.out.println("Before invoking: " + method.getName());
        // 調(diào)用真實(shí)主題的對(duì)應(yīng)方法
        Object result = method.invoke(realObject, args);
        // 額外的處理,比如記錄日志
        System.out.println("After invoking: " + method.getName());
        return result;
    }
}

在使用時(shí),我們可以這樣創(chuàng)建動(dòng)態(tài)代理對(duì)象并進(jìn)行文件上傳:

import java.lang.reflect.Proxy;
public class Main {
    public static void main(String[] args) {
        // 創(chuàng)建真實(shí)主題
        FileUploader realFileUploader = new RealFileUploader();
        // 創(chuàng)建動(dòng)態(tài)代理的處理器
        InvocationHandler handler = new DynamicProxyHandler(realFileUploader);
        // 創(chuàng)建代理類
        FileUploader proxyFileUploader = (FileUploader) Proxy.newProxyInstance(
                FileUploader.class.getClassLoader(),
                new Class[]{FileUploader.class},
                handler
        );
        // 通過動(dòng)態(tài)代理進(jìn)行文件上傳
        proxyFileUploader.upload("example.txt");
    }
}

運(yùn)行上述代碼,輸出將會(huì)是:

Before invoking: upload
Uploading file: example.txt
After invoking: upload

同樣,通過動(dòng)態(tài)代理,我們?cè)谖募蟼髑昂蟪晒μ砑恿祟~外的處理(記錄日志),同時(shí)客戶端代碼無(wú)需關(guān)心具體的日志記錄邏輯,實(shí)現(xiàn)了解耦。動(dòng)態(tài)代理在很多場(chǎng)景下非常有用,例如AOP(面向切面編程)等。

CGLIB代理

CGLIB(Code Generation Library)是一個(gè)開源的第三方庫(kù),用于在Java運(yùn)行時(shí)生成字節(jié)碼并創(chuàng)建代理類。與Java標(biāo)準(zhǔn)庫(kù)中的動(dòng)態(tài)代理(基于接口)不同,CGLIB代理可以代理普通類,即使它們沒有實(shí)現(xiàn)任何接口。CGLIB使用ASM庫(kù)來(lái)生成字節(jié)碼,并通過繼承的方式創(chuàng)建代理類,因此也被稱為子類代理。CGLIB廣泛用于各種框架和庫(kù)中,如Spring AOP。

下面詳細(xì)介紹CGLIB代理的結(jié)構(gòu)和示例:

  1. 示例代碼: 假設(shè)有一個(gè)簡(jiǎn)單的類 Calculator ,我們希望在其方法執(zhí)行前后記錄日志,可以使用CGLIB代理。

首先,引入CGLIB庫(kù),可以通過Maven添加依賴:

<dependency>
    <groupId>cglib</groupId>
    <artifactId>cglib</artifactId>
    <version>版本號(hào)</version>
</dependency>

然后,定義普通類 Calculator

public class Calculator {
    public int add(int a, int b) {
        return a + b;
    }
}

接下來(lái),創(chuàng)建一個(gè)代理類生成器 CalculatorProxyGenerator

import net.sf.cglib.proxy.Enhancer;
import net.sf.cglib.proxy.MethodInterceptor;
import net.sf.cglib.proxy.MethodProxy;
import java.lang.reflect.Method;
public class CalculatorProxyGenerator implements MethodInterceptor {
    private Object target;
    public CalculatorProxyGenerator(Object target) {
        this.target = target;
    }
    public Object createProxy() {
        Enhancer enhancer = new Enhancer();
        enhancer.setSuperclass(target.getClass());
        enhancer.setCallback(this);
        return enhancer.create();
    }
    @Override
    public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable {
        System.out.println("Before invoking: " + method.getName());
        Object result = proxy.invokeSuper(obj, args);
        System.out.println("After invoking: " + method.getName());
        return result;
    }
}

intercept 方法中,我們執(zhí)行了代理類的方法(通過 proxy.invokeSuper(obj, args) ),在方法執(zhí)行前后添加了額外的處理。

最后,在使用時(shí),我們可以這樣創(chuàng)建代理對(duì)象并調(diào)用方法:

public class Main {
    public static void main(String[] args) {
        Calculator calculator = new Calculator();
        CalculatorProxyGenerator proxyGenerator = new CalculatorProxyGenerator(calculator);
        Calculator proxyCalculator = (Calculator) proxyGenerator.createProxy();
        int result = proxyCalculator.add(3, 5);
        System.out.println("Result: " + result);
    }
}

運(yùn)行上述代碼,輸出將會(huì)是:

Before invoking: add
After invoking: add
Result: 8

這樣,通過CGLIB代理,我們成功在方法執(zhí)行前后添加了額外的處理(記錄日志),實(shí)現(xiàn)了解耦。CGLIB代理在不需要接口的情況下也能很好地完成代理任務(wù),但由于它是通過繼承的方式生成代理類,可能會(huì)影響某些場(chǎng)景,比如無(wú)法代理 final 方法。

動(dòng)態(tài)代理與CGLIB代理的區(qū)別

Spring在5.X之前默認(rèn)的動(dòng)態(tài)代理實(shí)現(xiàn)一直是jdk動(dòng)態(tài)代理。但是從5.X開始,spring就開始默認(rèn)使用Cglib來(lái)作為動(dòng)態(tài)代理實(shí)現(xiàn)。并且springboot從2.X開始也轉(zhuǎn)向了Cglib動(dòng)態(tài)代理實(shí)現(xiàn)。

為什么spring體系整體轉(zhuǎn)投Cglib呢,jdk動(dòng)態(tài)代理又有什么缺點(diǎn)呢?

  • jdk動(dòng)態(tài)代理只能基于接口,代理生成的對(duì)象只能賦值給接口變量,而Cglib就不存在這個(gè)問題,Cglib是通過生成子類來(lái)實(shí)現(xiàn)的,代理對(duì)象既可以賦值給實(shí)現(xiàn)類,又可以賦值給接口。
  • Cglib速度比jdk動(dòng)態(tài)代理更快,性能更好。

以上就是一文搞懂Java的三種代理模式(靜態(tài)代理、動(dòng)態(tài)代理和cglib代理)的詳細(xì)內(nèi)容,更多關(guān)于Java代理模式的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!

相關(guān)文章

  • Servlet簡(jiǎn)單實(shí)現(xiàn)登錄功能

    Servlet簡(jiǎn)單實(shí)現(xiàn)登錄功能

    這篇文章主要為大家詳細(xì)介紹了Servlet簡(jiǎn)單實(shí)現(xiàn)登錄功能,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2021-03-03
  • SpringBoot實(shí)現(xiàn)接口的各種參數(shù)校驗(yàn)的示例

    SpringBoot實(shí)現(xiàn)接口的各種參數(shù)校驗(yàn)的示例

    本文主要介紹了SpringBoot實(shí)現(xiàn)接口的各種參數(shù)校驗(yàn)的示例,文中通過示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2022-01-01
  • springboot+maven快速構(gòu)建項(xiàng)目的示例代碼

    springboot+maven快速構(gòu)建項(xiàng)目的示例代碼

    本篇文章主要介紹了springboot+maven快速構(gòu)建項(xiàng)目的示例代碼,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2017-08-08
  • java實(shí)現(xiàn)電話本系統(tǒng)

    java實(shí)現(xiàn)電話本系統(tǒng)

    這篇文章主要為大家詳細(xì)介紹了java實(shí)現(xiàn)電話本系統(tǒng),文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2022-05-05
  • 一文帶你了解SpringBoot的啟動(dòng)原理

    一文帶你了解SpringBoot的啟動(dòng)原理

    大家通常只需要給一個(gè)類添加一個(gè)@SpringBootApplication 注解,然后再加一個(gè)main 方法里面固定的寫法 SpringApplication.run(Application.class, args);那么spring boot 到底是如何啟動(dòng)服務(wù)的呢,接下來(lái)咱們通過源碼解析,需要的朋友可以參考下
    2023-05-05
  • 詳解MyBatis-Plus Wrapper條件構(gòu)造器查詢大全

    詳解MyBatis-Plus Wrapper條件構(gòu)造器查詢大全

    這篇文章主要介紹了詳解MyBatis-Plus Wrapper條件構(gòu)造器查詢大全,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧
    2020-08-08
  • Java中的延遲隊(duì)列DelayQueue詳細(xì)解析

    Java中的延遲隊(duì)列DelayQueue詳細(xì)解析

    這篇文章主要介紹了Java中的延遲隊(duì)列DelayQueue詳細(xì)解析,JDK自身支持延遲隊(duì)列的數(shù)據(jù)結(jié)構(gòu),其實(shí)類:java.util.concurrent.DelayQueue,<BR>我們通過閱讀源碼的方式理解該延遲隊(duì)列類的實(shí)現(xiàn)過程,需要的朋友可以參考下
    2023-12-12
  • Java求10到100000之間的水仙花數(shù)算法示例

    Java求10到100000之間的水仙花數(shù)算法示例

    這篇文章主要介紹了Java求10到100000之間的水仙花數(shù)算法,結(jié)合實(shí)例形式分析了水仙花數(shù)的概念及相應(yīng)的java算法實(shí)現(xiàn)技巧,需要的朋友可以參考下
    2017-10-10
  • springboot使用過濾器詳解

    springboot使用過濾器詳解

    本文主要介紹了過濾器的基本概念,過濾器的生命周期,以及如何通過注解方式和非注解方式實(shí)現(xiàn)過濾器,過濾器是客戶端與服務(wù)器資源文件之間的一道過濾網(wǎng),能夠幫助我們過濾不符合要求的請(qǐng)求,通常用作Session校驗(yàn)
    2024-10-10
  • FastJson時(shí)間格式化問題避坑經(jīng)驗(yàn)分享

    FastJson時(shí)間格式化問題避坑經(jīng)驗(yàn)分享

    這篇文章主要為大家介紹了FastJson時(shí)間格式化問題避坑經(jīng)驗(yàn)分享,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪
    2022-08-08

最新評(píng)論

阳信县| 甘泉县| 依兰县| 仪陇县| 同德县| 盘山县| 河津市| 保德县| 北安市| 桓台县| 高邑县| 东乡| 平安县| 商水县| 新津县| 余干县| 青阳县| 眉山市| 三门县| 长治市| 莱西市| 文昌市| 化隆| 利辛县| 揭东县| 广德县| 巫溪县| 夏河县| 临桂县| 靖州| 竹溪县| 潮州市| 恩平市| 陕西省| 大连市| 诏安县| 当涂县| 沙湾县| 襄汾县| 无棣县| 石家庄市|