面試常問的設計模式之代理模式的詳細解析!分析說明靜態代理模式和動態代理模式

攻城獅Chova發表於2022-02-10

Proxy-代理模式

代理模式

  • 代理模式: Proxy Pattern. 指為物件提供一種代理,用以控制對這個物件的訪問. 是一種結構型模式
    在這裡插入圖片描述
  • 代理模式包含三種角色:
    • 抽象角色Subject: 宣告真實角色和代理角色共同介面方法.該類可以是介面也可以是抽象類
    • 代理角色ProxySubject: 代理類. 代理物件內部包含對真實物件的引用,同時代理物件提供與真實物件相同的介面,可以代替真實物件. 同時,代理物件可以在執行真實物件操作時,附加其餘的操作,相當於對真實物件進行封裝
    • 真實角色RealSubject: 被代理類. 進行代理的真實物件,負責執行系統的真正的邏輯業務物件.呼叫真實物件方法,都要經過代理角色進行代理
  • 一般代理可以理解為程式碼增強,實際上就是在原始碼邏輯前後增加一些處理邏輯,而呼叫者無感知.代理模式屬於結構型模式,分為靜態代理和動態代理
  • 代理模式通用寫法

靜態代理

  • 靜態代理: 需要定義介面或者父類,被代理的物件和代理物件需要實現相同的介面或者相同的父類
  • 優點:
    • 可以做到在不修改目標物件的功能前提下,對目標功能進行擴充套件
  • 缺點:
    • 因為代理物件需要與真實物件實現同樣的介面,所以會有很多代理類
    • 如果介面增加方法,真實物件與代理物件都要進行維護
  • 靜態代理示例

動態代理

  • 動態代理特點:
    • 代理物件不需要實現介面
    • 動態代理是利用JDKAPI, 動態地在記憶體中構建代理物件.需要指定建立的代理物件或者目標物件實現的介面型別

Java動態代理

  • JavaJDK動態代理API所在的包 : java.lang.reflect.Proxy
  • JDK實現動態代理只需要使用newProxyInstance() 方法:
/**
 * 獲取指定介面的代理類例項,該代理類將方法呼叫分配給指定的呼叫處理程式
 * 該方法相當於:
 * 	Proxy.getProxyClass(loader, interfaces)
 *       .getConstructor(new Class[] { InvocationHandler.class })
 *       .newInstance(new Object[] { handler })
 *       .getConstructor(new Object[] { InvocationHandler.class });  
 * 
 * @param loader 指定當前真實物件使用的類載入器,獲取載入器的方法是固定的
 * @param interfaces 真實物件實現的介面型別,使用泛型的方式確認型別
 * @param h 事件處理,執行真實物件的方法時,會觸發事件處理器的方法,會將當前執行目標物件的方法作為引數傳入
 */
public static Object newProxyInstance(ClassLoader loader, Class<?>[] interfaces, InvocationHandler h);
  • 動態代理示例
  • Java動態代理要求被代理的物件必須是一個實現了介面的物件:
    • 原因在於Java動態代理生成代理類時預設繼承的Proxy
    • 根據Java的單繼承多實現的特性,只能實現對介面物件的代理

CGLIB代理

  • 靜態代理模式和動態代理模式要求目標物件是一個實現了介面的物件
    • 目標物件有時候只是一個單獨的物件,並沒有實現任何介面
    • 這時候可以使用目標物件子類的方式實現代理,即CGLIB代理
  • CGLIB代理: 子類代理. 在記憶體中構建真實物件類的子類物件實現對真實物件的代理
    • Java動態代理的物件必須實現一個或者多個介面.如果需要代理沒有是實現介面的類就可以使用CGLIB代理
    • CGLIB是一個高效能的程式碼生成包,可以在執行時期擴充套件java類和實現java介面,經常被應用在Spring AOP
    • CGLIB的底層是通過使用一個小而快的位元組碼處理框架ASM來轉換位元組碼並生成新的類.不推薦直接使用ASM框架,因為這對JVM內部結構包括class檔案的格式和指令集有要求
  • CGLIB代理實現:
    • 需要引入cglib依賴,因為Spring中已經是包含cglib功能,所以引入了spring-core依賴即可
    • 引入cglib依賴後,就可以在記憶體中動態構建子包
    • 代理的類不能是final修飾的類,否則會報錯
    • 真實物件的方法如果是final或者static, 就會被攔截,不會執行真實物件的額外業務方法
  • CGLIB代理示例

代理模式和裝飾器模式區別

  • UML類圖基本沒有區別,都是實現同一個介面,一個類包裝另一個類

代理模式

  • 控制訪問:
    • 為真實物件提供一種代理用於控制對這個物件的訪問
    • 在不改變介面的前提下,控制物件的訪問

裝飾器模式

  • 新增行為:
    • 動態的新增或者組合物件的行為
    • 在不改變介面的前提下,動態擴充套件物件的功能
  • 裝飾器模式的核心: 動態地將屬性,功能和責任附加到物件上

相關文章