国产 无码 综合区,色欲AV无码国产永久播放,无码天堂亚洲国产AV,国产日韩欧美女同一区二区

設計模式-代理模式Proxy

這篇具有很好參考價值的文章主要介紹了設計模式-代理模式Proxy。希望對大家有所幫助。如果存在錯誤或未考慮完全的地方,請大家不吝賜教,您也可以點擊"舉報違法"按鈕提交疑問。

代理模式 (Proxy)

代理設計模式(Proxy Design Pattern)是一種結(jié)構(gòu)型設計模式,它為其他對象提供一個代理,以控制對這個對象的訪問。代理模式可以用于實現(xiàn)懶加載、安全訪問控制、日志記錄等功能。

在設計模式中,代理模式可以分為靜態(tài)代理和動態(tài)代理。靜態(tài)代理是指代理類在編譯時就已經(jīng)確定,而動態(tài)代理是指代理類在運行時動態(tài)生成。

1) 靜態(tài)代理

1.a) 原理解析

在不改變原始類(或叫被代理類)代碼的情況下,通過引入代理類來給原始類附加功能。

1.b) 使用場景

1.緩存代理

緩存代理通常會在內(nèi)部維護一個緩存數(shù)據(jù)結(jié)構(gòu),如 HashMap 或者 LinkedHashMap,用來存儲已經(jīng)處理過的請求及其結(jié)果。

假設有一個數(shù)據(jù)查詢接口,它從數(shù)據(jù)庫或其他數(shù)據(jù)源中檢索數(shù)據(jù)。在沒有緩存代理的情況下,每次查詢都需要訪問數(shù)據(jù)庫,這可能會導致較高的資源消耗和延遲。通過引入緩存代理,我們可以將查詢結(jié)果存儲在內(nèi)存中,從而避免重復查詢數(shù)據(jù)庫。

public interface DataQuery {
    String query(String queryKey);
}
public class DatabaseDataQuery implements DataQuery {
    @Override
    public String query(String queryKey) {
        // 使用數(shù)據(jù)源從數(shù)據(jù)庫查詢數(shù)據(jù)很慢
        return "result";
    }
}

創(chuàng)建一個緩存代理類,它同樣實現(xiàn)了 DataQuery 接口,并在內(nèi)部使用HashMap 作為緩存:

public class DatabaseDataQueryProxy implements DataQuery {
    // 實現(xiàn)緩存,需要數(shù)據(jù)結(jié)構(gòu)
    private Map<String, String> cache = new HashMap<>(256);

    // 你代理誰,就要持有誰
    private DatabaseDataQuery dataQuery;

    public DatabaseDataQueryProxy() {
        // 1.屏蔽被代理對象
        this.dataQuery = new DatabaseDataQuery();
    }

    @Override
    public String query(String queryKey) {
        // 2.對被代理對象的方法做增強
        // 2.1.查詢緩存,命中則返回
        String result = cache.get(queryKey);
        if (result != null) {
            System.out.println("命中緩存,走緩存");
            return result;
        }

        // 2.2.未命中,則查詢數(shù)據(jù)庫
        result = dataQuery.query(queryKey);
        // 2.2.1.如果有結(jié)果,需要將結(jié)果保存到緩存中,再返回
        if (result != null) {
            cache.put(queryKey, result);
        }
        System.out.println("未命中,走持久層");
        return result;
    }
}
// 測試代碼
@Test
void test() {
    DataQuery dataQuery = new DatabaseDataQueryProxy();

    String value = dataQuery.query("key1");
    System.out.println(value);

    value = dataQuery.query("key1");
    System.out.println(value);

    value = dataQuery.query("key2");
    System.out.println(value);
}

2.安全代理

用于控制對真實主題對象的訪問。通過安全代理,可以實現(xiàn)訪問控制、權(quán)限驗證等安全相關(guān)功能。

假設我們有一個敏感數(shù)據(jù)查詢接口,只有具有特定權(quán)限的用戶才能訪問:

3.虛擬代理

在需要時延遲創(chuàng)建耗時或資源密集型對象。虛擬代理在初始訪問時才創(chuàng)建實際對象,之后將直接使用該對象。這可以避免在實際對象尚未使用的情況下就創(chuàng)建它,從而節(jié)省資源。

以下是一個虛擬代理的應用示例:

假設我們有一個大型圖片類,它從網(wǎng)絡加載圖像。由于圖像可能非常大,我們希望在需要顯示時才加載它。為了實現(xiàn)這一點,我們可以創(chuàng)建一個虛擬代理來代表大型圖片類。

4.遠程代理

用于訪問位于不同地址空間的對象。遠程代理可以為本地對象提供與遠程對象相同的接口,使得客戶端可以透明地訪問遠程對象。通常,遠程代理需要處理網(wǎng)絡通信、序列化和反序列化等細節(jié)。

1.c) 靜態(tài)代理步驟總結(jié)

通過前四個案例,我們也大致了解了靜態(tài)代理的使用方式,其大致流程如下:

  • 1.創(chuàng)建一個接口,定義 代理類和被代理類 實現(xiàn)共同的接口
  • 2.創(chuàng)建被代理類,實現(xiàn)這個接口,并且在其中定義實現(xiàn)方法
  • 3.創(chuàng)建代理類,也要實現(xiàn)這個接口,同時在其中定義一個被代理類的對象作為成員變量
  • 4.在代理類中實現(xiàn)接口中的方法,方法中調(diào)用 被代理類 中的對應方法
  • 5.通過創(chuàng)建代理對象,并調(diào)用其方法,方法增強

這樣,被代理類的方法就會被代理類所覆蓋,實現(xiàn)了對被代理類的增強或修改。

2) 動態(tài)代理

靜態(tài)代理需要手動編寫代理類代理類與被代理類實現(xiàn)相同的接口或繼承相同的父類,對被代理對象進行包裝。在程序運行前,代理類的代碼就已經(jīng)生成,并在程序運行時調(diào)用。靜態(tài)代理的優(yōu)點是簡單易懂,缺點是需要手動編寫代理類,代碼復雜度較高,且不易擴展。

動態(tài)代理是在程序運行時動態(tài)生成代理類,無需手動編寫代理類,大大降低了代碼的復雜度。動態(tài)代理一般使用 Java 提供的反射機制實現(xiàn),可以對任意實現(xiàn)了接口的類進行代理。動態(tài)代理的優(yōu)點是靈活性高,可以根據(jù)需要動態(tài)生成代理類,缺點是性能相對較低,由于使用反射機制,在運行時會產(chǎn)生額外的開銷。

2.a) 基于 JDK 的動態(tài)代理實現(xiàn)步驟

使用緩存代理的例子

public interface DataQuery {
    String query(String queryKey);
}
public class DatabaseDataQuery implements DataQuery {
    @Override
    public String query(String queryKey) {
        // 使用數(shù)據(jù)源從數(shù)據(jù)庫查詢數(shù)據(jù)很慢
        return "result";
    }
}

創(chuàng)建一個代理類,實現(xiàn) InvocationHandler 接口,實現(xiàn)invoke()方法,并在其中定義一個被代理類的對象作為屬性。

public class CacheInvocationHandler implements InvocationHandler {

    private Map<String, String> cache = new HashMap<>(256);

    private DatabaseDataQuery databaseDataQuery;

    public CacheInvocationHandler() {
        this.databaseDataQuery = new DatabaseDataQuery();
    }

    public CacheInvocationHandler(DatabaseDataQuery databaseDataQuery) {
        this.databaseDataQuery = databaseDataQuery;
    }

    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        // 1.判斷是哪一個方法 (只對query方法做緩存)
        String result;
        if ("query".equals(method.getName())) {
            // 2.查緩存
            // 2.1.命中直接返回
            result = cache.get(args[0].toString());
            if (result != null) {
                System.out.println("從緩存拿數(shù)據(jù)");
                return result;
            }

            // 2.2.未命中,查詢數(shù)據(jù)庫 (需要代理實例)
            result = (String) method.invoke(databaseDataQuery, args);

            // 3.查詢到了,進行緩存
            cache.put(args[0].toString(), result);
            return result;
        }

        // 當其他的方法被調(diào)用,不希望被干預,直接調(diào)用原生的方法
        return method.invoke(databaseDataQuery, args);
    }
}

主要業(yè)務邏輯 (測試代碼)

@Test
void testJdkDynamicProxy() {
    // jdk提供的代理實現(xiàn),主要是使用Proxy類來實現(xiàn)
    // 參數(shù)1 classLoader:被代理類的類加載器
    ClassLoader classLoader = Thread.currentThread().getContextClassLoader();
    // 參數(shù)2 代理類需要實現(xiàn)的接口數(shù)組
    Class[] interfaces = new Class[]{DataQuery.class};
    // 參數(shù)3 InvocationHandler
    InvocationHandler invocationHandler = new CacheInvocationHandler();

    DataQuery dataQuery = (DataQuery) Proxy.newProxyInstance(classLoader, interfaces, invocationHandler);

    // 調(diào)用query方法時,實際上是調(diào)用了invoke()方法
    String result = dataQuery.query("key1");
    System.out.println(result);
    result = dataQuery.query("key1");
    System.out.println(result);
    result = dataQuery.query("key2");
    System.out.println(result);

    System.out.println("-----------------");
    result = dataQuery.queryAll();
    System.out.println(result);
}
2.b) 基于 CGLIB 的動態(tài)代理實現(xiàn)步驟

基于 CGLIB 的動態(tài)代理需要使用 net.sf.cglib.proxy.Enhancer 類和 net.sf.cglib.proxy.MethodInterceptor 接口。

1.創(chuàng)建一個被代理類,定義需要被代理的方法 (以DatabaseDataQuery為例)

public class DatabaseDataQuery {
    public String query(String queryKey) {
        // 使用數(shù)據(jù)源從數(shù)據(jù)庫查詢數(shù)據(jù)很慢
        System.out.println("正在從數(shù)據(jù)庫中查詢數(shù)據(jù)");
        return "result";
    }

    public String queryAll() {
        System.out.println("正在從數(shù)據(jù)庫中查詢數(shù)據(jù)");
        return "query All result";
    }
}

2.創(chuàng)建一個方法攔截器類,實現(xiàn) MethodInterceptor 接口,并在其中定義一個被代理類的對象作為屬性。

  • intercept 方法中,我們可以對被代理對象的方法進行增強
public class CacheMethodInterceptor implements MethodInterceptor {
    private Map<String, String> cache = new HashMap<>(256);

    private DatabaseDataQuery databaseDataQuery;

    public CacheMethodInterceptor() {
        this.databaseDataQuery = new DatabaseDataQuery();
    }

    public CacheMethodInterceptor(DatabaseDataQuery databaseDataQuery) {
        this.databaseDataQuery = databaseDataQuery;
    }

    @Override
    public Object intercept(Object o, Method method, Object[] args, MethodProxy methodProxy) throws Throwable {
        // 1.判斷是哪一個方法
        String result;
        if ("query".equals(method.getName())) {
            // 2.查詢緩存,命中則直接返回
            result = cache.get(args[0].toString());
            if (result != null) {
                System.out.println("從緩存中提取數(shù)據(jù)");
                return result;
            }

            // 3.未命中,查詢數(shù)據(jù)庫
            result = (String) method.invoke(databaseDataQuery, args);

            // 4.緩存到緩存中
            cache.put(args[0].toString(), result);
            return result;
        }

        return method.invoke(databaseDataQuery, args);
    }
}

3.在使用代理類時,創(chuàng)建被代理類的對象和代理類的對象,并使用 Enhancer.create 方法生成代理對象。

@Test
void testCgkibDynamicProxy() {
    // cglib通過enhancer
    Enhancer enhancer = new Enhancer();
    // 1.設置父類
    enhancer.setSuperclass(DatabaseDataQuery.class);
    // 2.設置一個方法攔截器,用來攔截方法
    enhancer.setCallback(new CacheMethodInterceptor());
    // 3.創(chuàng)建代理類
    DatabaseDataQuery databaseDataQuery = (DatabaseDataQuery) enhancer.create();

    String value = databaseDataQuery.query("key1");
    System.out.println(value);
    value = databaseDataQuery.query("key1");
    System.out.println(value);
    value = databaseDataQuery.query("key2");
    System.out.println(value);
}
2.c) Spring中aop的使用步驟

在 Spring 中,AOP(面向切面編程)提供了一種有效的方式來對程序中的多個模塊進行橫切關(guān)注點的處理,例如日志、事務、緩存、安全等。使用 Spring AOP,可以在程序運行時動態(tài)地將代碼織入到目標對象中,從而實現(xiàn)對目標對象的增強。

Spring AOP 的使用步驟如下:

1.引入 AOP 相關(guān)依賴

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-aop</artifactId>
    <version>2.3.9.RELEASE</version>
</dependency>

2.在Main中開啟自動代理@EnableAspectJAutoProxy

@SpringBootApplication
@EnableAspectJAutoProxy
public class Main {
    public static void main(String[] args) {
        SpringApplication.run(Main.class, args);
    }
}

3.定義接口和實現(xiàn)類,并將具體實現(xiàn)注入容器 (以DatabaseDataQuery為例)

// 接口
public interface DataQuery {
    String query(String queryKey);
}

// 實現(xiàn)類
@Component
public class DatabaseDataQuery implements DataQuery {
    @Override
    public String query(String queryKey) {
        // 使用數(shù)據(jù)源從數(shù)據(jù)庫查詢數(shù)據(jù)很慢
        System.out.println("正在從數(shù)據(jù)庫中查詢數(shù)據(jù)");
        return "result";
    }
}

4.定義切面類,對方法做增強

  • @Pointcut() 對某包下的某個類的某個方法做增強:.. 代表任意方法
  • @Around() 定義增強
@Component
@Aspect
public class CacheAspectj {

    private static Map<String,String> cache = new ConcurrentHashMap<>(256);

    @Pointcut("execution(* com.dcy.structural.proxy.dynamicProxy.aop.impl.DatabaseDataQuery.query(..))")
    public void pointcut() {}

    @Around("pointcut()")
    public String around(ProceedingJoinPoint joinPoint) {

        // 1.查詢緩存
        Object[] args = joinPoint.getArgs();
        String key = args[0].toString();

        // 1.1.命中則返回
        String result = cache.get(key);
        if (result != null) {
            System.out.println("數(shù)據(jù)從緩存中提取");
            return result;
        }

        // 2.未命中,查詢數(shù)據(jù)庫,實際上是調(diào)用被代理bean的方法
        try {
            result = joinPoint.proceed().toString();
            // 如果查詢有結(jié)果,進行緩存
            cache.put(key, result);
        } catch (Throwable e) {
            throw new RuntimeException(e);
        }

        return result;
    }
}

5.測試用例文章來源地址http://www.zghlxwxcb.cn/news/detail-691908.html

@SpringBootTest
public class AopTest {

    @Resource
    private DataQuery dataQuery;

    @Test
    void testSpringAop() {
        String result = dataQuery.query("key1");
        System.out.println(result);
        result = dataQuery.query("key1");
        System.out.println(result);
        result = dataQuery.query("key2");
        System.out.println(result);
    }

}

到了這里,關(guān)于設計模式-代理模式Proxy的文章就介紹完了。如果您還想了解更多內(nèi)容,請在右上角搜索TOY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!

本文來自互聯(lián)網(wǎng)用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權(quán),不承擔相關(guān)法律責任。如若轉(zhuǎn)載,請注明出處: 如若內(nèi)容造成侵權(quán)/違法違規(guī)/事實不符,請點擊違法舉報進行投訴反饋,一經(jīng)查實,立即刪除!

領(lǐng)支付寶紅包贊助服務器費用

相關(guān)文章

  • 設計模式之代理模式(Proxy)的C++實現(xiàn)

    設計模式之代理模式(Proxy)的C++實現(xiàn)

    在組件的開發(fā)過程中,有些對象由于某種原因(比如對象創(chuàng)建的開銷很大,或者對象的一些操作需要做安全控制,或者需要進程外的訪問等),會使Client使用者在操作這類對象時可能會存在問題:(1)使用者直接訪問這種對象會使系統(tǒng)帶來很多麻煩。(2)或者使用者使不能

    2024年02月12日
    瀏覽(19)
  • 設計模式——1_6 代理(Proxy)

    設計模式——1_6 代理(Proxy)

    詩有可解不可解,若鏡花水月勿泥其跡可也 —— 謝榛 為其他對象提供一種代理以控制對這個對象的訪問 某天,你突發(fā)奇想,想做一個可以展示指定文件夾內(nèi)所有圖片的桌面應用。這個應用很簡單,遍歷文件夾,發(fā)現(xiàn)圖片文件,把圖片加載到GUI上的圖片列表里,顯示圖片名和

    2024年01月25日
    瀏覽(18)
  • 設計模式之代理模式(Proxy),以C++為例,實現(xiàn)遠程代理、虛擬代理、保護代理等。

    設計模式之代理模式(Proxy),以C++為例,實現(xiàn)遠程代理、虛擬代理、保護代理等。

    ? ? ? ? 兄弟姐妹們好,又是好久沒有更新了,今天給大家簡單介紹代理模式,一個很簡單的設計模式,旨在不改變原對象的情況下通過代理對象來控制對原對象的訪問。代理模式根據(jù)具體情況還可以分為遠程代理、虛擬代理、保護代理等,下面來介紹一下。 目錄 ?一、代理

    2023年04月09日
    瀏覽(29)
  • 設計模式- 代理模式(Proxy Pattern)結(jié)構(gòu)|原理|優(yōu)缺點|場景|示例

    ? ??????????????????????????????????設計模式(分類)????????設計模式(六大原則)? ? ? ? 創(chuàng)建型(5種) ????????工廠方法?????????抽象工廠模式????????單例模式????????建造者模式????????原型模式 ? ? 結(jié)構(gòu)型(7種) ?????

    2024年04月24日
    瀏覽(27)
  • Java設計模式 (三) 代理設計模式

    什么是代理設計模式? 代理設計模式是一種結(jié)構(gòu)型設計模式,它允許創(chuàng)建一個代理對象,用于控制對其他對象的訪問。代理模式通常用于在訪問對象時添加一些附加操作,而不是直接訪問真實對象。代理模式可以在不改變原始類代碼的情況下,通過引入代理類來增強功能。 代

    2024年02月12日
    瀏覽(25)
  • Java設計模式(十三)代理模式

    一、概述 代理模式是一種結(jié)構(gòu)型設計模式,它提供了一個代理對象,充當被代理對象的接口,以控制對被代理對象的訪問。代理模式可以在不修改被代理對象的情況下,增加額外的功能或控制訪問方式。 二、代碼 以下是一個示例代碼,說明代理模式的使用: 在上述代碼中,

    2024年02月04日
    瀏覽(24)
  • 【Java設計模式005】代理模式

    由于一些特定原因某些對象不適合或者不能直接引用目標對象,這時就可以使用代理模式。代理模式為目標對象提供一個代理以控制訪問對象對目標對象的訪問??蛻舳酥荒苤苯釉L問代理對象,不能直接訪問目標對象,這么做確保了目標對象的安全。生活中一個常見的例子就

    2024年02月12日
    瀏覽(19)
  • 基于Java的設計模式 - 代理模式

    代理模式是一種使用代理對象來執(zhí)行目標對象的方法并在代理對象中增強目標對象方法的一種設計模式。簡單來講就是在不修改目標對象的基礎上,增強主業(yè)務邏輯的設計模式。 代理模式基本可分為三種 靜態(tài)代理 JDK動態(tài)代理 CGLIB動態(tài)代理 上述簡單分就是靜態(tài)和動態(tài)代理,靜

    2024年02月07日
    瀏覽(21)
  • Java設計模式---單例 工廠 代理模式

    單例模式是設計模式中的一種,屬于創(chuàng)建型模式。在軟件工程中,單例模式確保一個類只有一個實例,并提供一個全局訪問點。這種模式常用于那些需要頻繁實例化然后引用,且創(chuàng)建新實例的開銷較大的類,例如數(shù)據(jù)庫連接池、緩存管理等。 意圖 :保證一個類僅有一個實例

    2024年01月24日
    瀏覽(28)
  • Java 與設計模式(13):代理模式

    代理模式是一種結(jié)構(gòu)型設計模式,用于在訪問對象時引入一個代理對象,以控制對實際對象的訪問。代理對象充當了客戶端和實際對象之間的中介,客戶端通過代理對象間接地訪問實際對象,從而可以在訪問過程中添加額外的邏輯或控制。代理模式可以提供對實際對象的保護

    2024年02月09日
    瀏覽(19)

覺得文章有用就打賞一下文章作者

支付寶掃一掃打賞

博客贊助

微信掃一掃打賞

請作者喝杯咖啡吧~博客贊助

支付寶掃一掃領(lǐng)取紅包,優(yōu)惠每天領(lǐng)

二維碼1

領(lǐng)取紅包

二維碼2

領(lǐng)紅包