日日操夜夜添-日日操影院-日日草夜夜操-日日干干-精品一区二区三区波多野结衣-精品一区二区三区高清免费不卡

公告:魔扣目錄網為廣大站長提供免費收錄網站服務,提交前請做好本站友鏈:【 網站目錄:http://www.ylptlb.cn 】, 免友鏈快審服務(50元/站),

點擊這里在線咨詢客服
新站提交
  • 網站:51998
  • 待審:31
  • 小程序:12
  • 文章:1030137
  • 會員:747

JAVA靜態代理

Java中的靜態代理是一種設計模式,它通過創建一個代理類來代替原始類,從而控制對原始類的訪問。代理類和原始類都實現相同的接口,使得客戶端在使用時無需關心具體的實現細節。靜態代理在編譯時就已經確定代理類和原始類的關系,因此稱為靜態代理。

下面是Java靜態代理UML類圖:

 

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

首先,定義抽象接口 FileUploader:

Java復制代碼public interface FileUploader {
    void upload(String file);
}

然后,實現真實上傳 RealFileUploader:

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

接下來,實現代理 ProxyFileUploader:

Java復制代碼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);

        // 調用真實主題的上傳方法
        realFileUploader.upload(file);

        // 額外的處理,比如記錄日志
        System.out.println("After uploading: " + file);
    }
}

在使用時,我們可以這樣創建代理類并進行文件上傳:

Java復制代碼public class MAIn {
    public static void main(String[] args) {
        // 創建真實主題
        FileUploader realFileUploader = new RealFileUploader();

        // 創建代理主題,并將真實主題傳入
        FileUploader proxyFileUploader = new ProxyFileUploader(realFileUploader);

        // 通過代理主題進行文件上傳
        proxyFileUploader.upload("example.txt");
    }
}

運行上述代碼,輸出將會是:

Java復制代碼Before uploading: example.txt
Uploading file: example.txt
After uploading: example.txt

Java動態代理

Java動態代理是一種在運行時創建代理類的機制,它允許在不提前知道代理類的具體類型的情況下,動態地創建一個代理對象來代替原始類。相比于靜態代理,動態代理更加靈活,可以代理任意的接口類型,不需要為每個被代理的類編寫專門的代理類,而是通過Java的反射機制在運行時動態生成代理類。動態代理主要使用java.lang.reflect.Proxy類和
java.lang.reflect.InvocationHandler接口來實現。動態代理又被稱為JDK代理或接口代理。

下面看下動態代理的UML圖:

 

示例代碼: 與前面的靜態代理示例相同,我們仍然使用文件上傳的接口FileUploader,其真實實現為RealFileUploader。接下來,我們將通過動態代理在上傳文件前后記錄日志。

首先,定義抽象主題接口 FileUploader 和實現真實主題 RealFileUploader,與之前相同,不再重復。

然后,實現 InvocationHandler 接口,創建動態代理的處理器類 DynamicProxyHandler:

Java復制代碼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());

        // 調用真實主題的對應方法
        Object result = method.invoke(realObject, args);

        // 額外的處理,比如記錄日志
        System.out.println("After invoking: " + method.getName());

        return result;
    }
}

在使用時,我們可以這樣創建動態代理對象并進行文件上傳:

Java復制代碼import java.lang.reflect.Proxy;

public class Main {
    public static void main(String[] args) {
        // 創建真實主題
        FileUploader realFileUploader = new RealFileUploader();

        // 創建動態代理的處理器
        InvocationHandler handler = new DynamicProxyHandler(realFileUploader);

        // 創建代理類
        FileUploader proxyFileUploader = (FileUploader) Proxy.newProxyInstance(
                FileUploader.class.getClassLoader(),
                new Class[]{FileUploader.class},
                handler
        );

        // 通過動態代理進行文件上傳
        proxyFileUploader.upload("example.txt");
    }
}

運行上述代碼,輸出將會是:

Java復制代碼Before invoking: upload
Uploading file: example.txt
After invoking: upload

同樣,通過動態代理,我們在文件上傳前后成功添加了額外的處理(記錄日志),同時客戶端代碼無需關心具體的日志記錄邏輯,實現了解耦。動態代理在很多場景下非常有用,例如AOP(面向切面編程)等。

CGLIB代理

CGLIB(Code Generation Library)是一個開源的第三方庫,用于在Java運行時生成字節碼并創建代理類。與Java標準庫中的動態代理(基于接口)不同,CGLIB代理可以代理普通類,即使它們沒有實現任何接口。CGLIB使用ASM庫來生成字節碼,并通過繼承的方式創建代理類,因此也被稱為子類代理。CGLIB廣泛用于各種框架和庫中,如Spring AOP。

下面詳細介紹CGLIB代理的結構和示例:

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

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

xml復制代碼<dependency>
    <groupId>cglib</groupId>
    <artifactId>cglib</artifactId>
    <version>版本號</version>
</dependency>

然后,定義普通類 Calculator:

Java復制代碼public class Calculator {
    public int add(int a, int b) {
        return a + b;
    }
}

接下來,創建一個代理類生成器 CalculatorProxyGenerator:

Java復制代碼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方法中,我們執行了代理類的方法(通過proxy.invokeSuper(obj, args)),在方法執行前后添加了額外的處理。

最后,在使用時,我們可以這樣創建代理對象并調用方法:

Java復制代碼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);
    }
}

運行上述代碼,輸出將會是:

Java復制代碼Before invoking: add
After invoking: add
Result: 8

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

動態代理與CGLIB代理的區別

Spring在5.X之前默認的動態代理實現一直是jdk動態代理。但是從5.X開始,spring就開始默認使用Cglib來作為動態代理實現。并且springboot從2.X開始也轉向了Cglib動態代理實現。

為什么spring體系整體轉投Cglib呢,jdk動態代理又有什么缺點呢?

  • jdk動態代理只能基于接口,代理生成的對象只能賦值給接口變量,而Cglib就不存在這個問題,Cglib是通過生成子類來實現的,代理對象既可以賦值給實現類,又可以賦值給接口。
  • Cglib速度比jdk動態代理更快,性能更好。


原文鏈接:
https://juejin.cn/post/7264920384888471610

分享到:
標簽:Java
用戶無頭像

網友整理

注冊時間:

網站:5 個   小程序:0 個  文章:12 篇

  • 51998

    網站

  • 12

    小程序

  • 1030137

    文章

  • 747

    會員

趕快注冊賬號,推廣您的網站吧!
最新入駐小程序

數獨大挑戰2018-06-03

數獨一種數學游戲,玩家需要根據9

答題星2018-06-03

您可以通過答題星輕松地創建試卷

全階人生考試2018-06-03

各種考試題,題庫,初中,高中,大學四六

運動步數有氧達人2018-06-03

記錄運動步數,積累氧氣值。還可偷

每日養生app2018-06-03

每日養生,天天健康

體育訓練成績評定2018-06-03

通用課目體育訓練成績評定