AVt天堂网 手机版,亚洲va久久久噜噜噜久久4399,天天综合亚洲色在线精品,亚洲一级Av无码毛片久久精品

當前位置:首頁 > 科技  > 軟件

詳解JDK動態代理和CGLib動態代理

來源: 責編: 時間:2023-12-06 09:19:24 269觀看
導讀代理模式代理模式(Proxy Pattern)是23種設計模式中的一種,屬于結構型設計模式。代理模式給某一個對象提供一個代理,并由代理對象控制原對象的引用。代理對象在客戶端和目標對象之間起到中介作用。舉個例子:你要去吃飯,你可

5yJ28資訊網——每日最新資訊28at.com

代理模式

代理模式(Proxy Pattern)是23種設計模式中的一種,屬于結構型設計模式。代理模式給某一個對象提供一個代理,并由代理對象控制原對象的引用。代理對象在客戶端和目標對象之間起到中介作用。5yJ28資訊網——每日最新資訊28at.com

舉個例子:你要去吃飯,你可以選擇自己在家做飯、吃飯、刷碗,所有的事情都自己做;也可以選擇去餐廳,自己只是吃飯,把做飯和刷碗的活兒都交給代理對象,也就是餐廳的工作人員。5yJ28資訊網——每日最新資訊28at.com

下圖是代理模式的通用類圖。結合例子,就很容易理解了。5yJ28資訊網——每日最新資訊28at.com

5yJ28資訊網——每日最新資訊28at.com

代理模式通用類圖5yJ28資訊網——每日最新資訊28at.com

代理模式包含如下角色:5yJ28資訊網——每日最新資訊28at.com

  • Subject (抽象主題角色) 抽象主題角色聲明了真實主題和代理主題的共同接口,這樣一來在任何使用真實主題 的地方都可以使用代理主題。客戶端需要針對抽象主題角色進行編程。
  • Proxy (代理主題角色) 代理主題角色內部包含對真實主題的引用,從而可以在任何時候操作真實主題對象。 在代理主題角色中提供一個與真實主題角色相同的接口,以便在任何時候都可以替代真實主體。代理主題角色還可以控制對真實主題的使用,負責在需要的時候創建和刪除真實主題對象,并對真實主題對象的使用加以約束。代理角色通常在客戶端調用所引用的真實主題操作之前或之后還需要執行其他操作,而不僅僅是單純的調用真實主題對象中的操作。
  • RealSubject (真實主題角色) 真實主題角色定義了代理角色所代表的真實對象,在真實主題角色中實現了真實的業務操作,客戶端可以通過代理主題角色間接調用真實主題角色中定義的方法。

代理模式可以分為靜態代理和動態代理兩種類型,而動態代理中又分為JDK動態代理和CGLIB代理兩種。5yJ28資訊網——每日最新資訊28at.com

JDK動態代理

在jdk的動態代理機制中,有幾個重要的角色:5yJ28資訊網——每日最新資訊28at.com

  • Interface:對于JDK Proxy,業務類是需要一個Interface的。
  • Proxy:Proxy類是動態產生的,這個類在調用Proxy.newProxyInstance()方法之后,產生一個Proxy類的實例。實際上,這個Proxy類也是存在的,不僅僅是類的實例,這個Proxy類可以保存在硬盤上。
  • Method:對于業務委托類的每個方法,現在Proxy類里面都不用靜態顯示出來。
  • InvocationHandler:這個類在業務委托類執行時,會先調用invoke方法。invoke方法再執行想要的代理操作,可以實現對業務方法的再包裝。

(1)InvocationHandler

每一個動態代理類都必須要實現InvocationHandler這個接口,并且每個代理類的實例都關聯了一個handler,當我們通過代理對象調用一個方法的時候,這個方法的調用就會被轉發為由InvocationHandler這個接口的 invoke 方法來進行調用。5yJ28資訊網——每日最新資訊28at.com

InvocationHandler這個接口的唯一一個方法 invoke 方法:5yJ28資訊網——每日最新資訊28at.com

Object invoke(Object proxy, Method method, Object[] args) throws Throwable

這個方法一共接受三個參數,那么這三個參數分別代表如下:5yJ28資訊網——每日最新資訊28at.com

  • proxy:指代JDK動態生成的最終代理對象
  • method:指代的是我們所要調用真實對象的某個方法的Method對象
  • args:指代的是調用真實對象某個方法時接受的參數

(2)Proxy

Proxy這個類的作用就是用來動態創建一個代理對象的類,它提供了許多的方法,但是我們用的最多的就是newProxyInstance 這個方法:5yJ28資訊網——每日最新資訊28at.com

public static Object newProxyInstance(ClassLoader loader, Class<?>[] interfaces, InvocationHandler handler) throws IllegalArgumentException

這個方法的作用就是得到一個動態的代理對象,其接收三個參數,我們來看看這三個參數所代表的含義:5yJ28資訊網——每日最新資訊28at.com

  • loader:ClassLoader對象,定義了由哪個ClassLoader來對生成的代理對象進行加載,即代理類的類加載器。
  • interfaces:Interface對象的數組,表示的是我將要給我需要代理的對象提供一組什么接口,如果我提供了一組接口給它,那么這個代理對象就宣稱實現了該接口(多態),這樣我就能調用這組接口中的方法了。
  • Handler:InvocationHandler對象,表示的是當我這個動態代理對象在調用方法的時候,會關聯到哪一個InvocationHandler對象上。

所以我們所說的DynamicProxy(動態代理類)是這樣一種class:它是在運行時生成的class,在生成它時你必須提供一組interface給它,然后該class就宣稱它實現了這些 interface。這個DynamicProxy其實就是一個Proxy,它不會做實質性的工作,在生成它的實例時你必須提供一個handler,由它接管實際的工作。5yJ28資訊網——每日最新資訊28at.com

(3)代碼實現

被代理對象:5yJ28資訊網——每日最新資訊28at.com

/** * 抽象主題角色 */interface Subject {    void eat();}/** * 真實主題角色 - 你自己 - 專注吃飯 */class YourSelf implements Subject{    @Override    public void eat() {        System.out.println("自己吃飯");    }}

代理對象:5yJ28資訊網——每日最新資訊28at.com

/** * 代理主題角色 - 餐廳 * 每次生成動態代理類對象時都需要指定一個實現了InvocationHandler接口的調用處理器對象 */class JdkProxySubject implements InvocationHandler {    // 這個就是我們要代理的真實對象,也就是真正執行業務邏輯的類    private Object target;    // 通過構造方法傳入這個被代理對象    public JdkProxySubject(Object target) {        super();        this.target = target;    }    // 創建代理對象    public Object createProxy() {        // 1.得到目標對象的類加載器        ClassLoader classLoader = target.getClass().getClassLoader();        // 2.得到目標對象的實現接口        Class<?>[] interfaces = target.getClass().getInterfaces();        // 3.第三個參數需要一個實現invocationHandler接口的對象        Object newProxyInstance = Proxy.newProxyInstance(classLoader, interfaces, this);        return newProxyInstance;    }    // 當代理對象調用真實對象的方法時,其會自動的跳轉到代理對象關聯的handler對象的invoke方法來進行調用    @Override    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {        System.out.println("餐廳工作人員做飯......");        Object invoke = method.invoke(target, args);        System.out.println("餐廳工作人員刷碗......");        return invoke;    }}

測試類:5yJ28資訊網——每日最新資訊28at.com

/** * 測試類 * @author tianxiaopeng@hxy * @date 2023/10/11 11:09 AM */public class ProxyTest {    public static void main(String[] args) {        // 1.創建對象        YourSelf yourSelf = new YourSelf();        // 2.創建代理對象        JdkProxySubject proxy = new JdkProxySubject(yourSelf);        // 3.調用代理對象的增強方法,得到增強后的對象        Subject createProxy = (Subject) proxy.createProxy();        createProxy.eat();    }}

CGLIB動態代理

JDK動態代理是通過重寫被代理對象實現的接口中的方法來實現,而CGLIB是通過繼承被代理對象來實現,和JDK動態代理需要實現指定接口一樣,CGLIB也要求代理對象必須要實現MethodInterceptor接口,并重寫其唯一的方法intercept。5yJ28資訊網——每日最新資訊28at.com

CGLib采用了非常底層的字節碼技術,其原理是通過字節碼技術為一個類創建子類,并在子類中采用方法攔截的技術攔截所有父類方法的調用,順勢織入橫切邏輯。(利用ASM開源包,對代理對象類的class文件加載進來,通過修改其字節碼生成子類來處理)5yJ28資訊網——每日最新資訊28at.com

注意:因為CGLIB是通過繼承目標類來重寫其方法來實現的,故而如果是final和private方法則無法被重寫,也就是無法被代理。5yJ28資訊網——每日最新資訊28at.com

<dependency>    <groupId>cglib</groupId>	<artifactId>cglib-nodep</artifactId>	<version>2.2</version></dependency>

(1)CGLib核心類

net.sf.cglib.proxy.Enhancer:主要增強類,通過字節碼技術動態創建委托類的子類實例。5yJ28資訊網——每日最新資訊28at.com

Enhancer可能是CGLIB中最常用的一個類,和Java1.3動態代理中引入的Proxy類差不多。和Proxy不同的是,Enhancer既能夠代理普通的class,也能夠代理接口。Enhancer創建一個被代理對象的子類并且攔截所有的方法調用(包括從Object中繼承的toString和hashCode方法)。Enhancer不能夠攔截final方法,例如Object.getClass()方法,這是由于Java final方法語義決定的。基于同樣的道理,Enhancer也不能對fianl類進行代理操作。這也是Hibernate為什么不能持久化final class的原因。5yJ28資訊網——每日最新資訊28at.com

net.sf.cglib.proxy.MethodInterceptor:常用的方法攔截器接口,需要實現intercept方法,實現具體攔截處理。5yJ28資訊網——每日最新資訊28at.com

public java.lang.Object intercept(java.lang.Object obj,                                   java.lang.reflect.Method method,                                   java.lang.Object[] args,                                   MethodProxy proxy) throws java.lang.Throwable{}
  • obj:動態生成的代理對象。
  • method:實際調用的方法。
  • args:調用方法入參。
  • net.sf.cglib.proxy.MethodProxy:java Method類的代理類,可以實現委托類對象的方法的調用;常用方法:methodProxy.invokeSuper(proxy, args);在攔截方法內可以調用多次。

(2)CGLib代理實例

創建被代理類。5yJ28資訊網——每日最新資訊28at.com

/** * 真實主題角色 - 你自己 - 專注吃飯 */class YourSelf {    public void eat(){        System.out.println("自己吃飯");    }}

創建代理類:5yJ28資訊網——每日最新資訊28at.com

/** * 代理主題角色 - 餐廳 */class ProxyCglib implements MethodInterceptor {    private Enhancer enhancer = new Enhancer();    public Object getProxy(Class clazz){        //設置需要創建子類的類        enhancer.setSuperclass(clazz);        enhancer.setCallback(this);        //通過字節碼技術動態創建子類實例        return enhancer.create();    }    //實現MethodInterceptor接口方法    public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable {        System.out.println("餐廳工作人員做飯......");        //通過代理類調用父類中的方法        Object result = proxy.invokeSuper(obj, args);        System.out.println("餐廳工作人員刷碗......");        return result;    }}

測試類:5yJ28資訊網——每日最新資訊28at.com

/** * 測試類 * @author tianxiaopeng@hxy * @date 2023/10/11 11:51 AM */public class CglibTest {    public static void main(String[] args) {        ProxyCglib proxy = new ProxyCglib();        //通過生成子類的方式創建代理類        YourSelf proxyImp = (YourSelf)proxy.getProxy(YourSelf.class);        proxyImp.eat();    }}

結果:5yJ28資訊網——每日最新資訊28at.com

餐廳工作人員做飯......自己吃飯餐廳工作人員刷碗......

(2)CGLIB動態代理實現分析

CGLib動態代理采用了FastClass機制,其分別為代理類和被代理類各生成一個FastClass,這個FastClass類會為代理類或被代理類的方法分配一個 index(int類型)。這個index當做一個入參,FastClass 就可以直接定位要調用的方法直接進行調用,這樣省去了反射調用,所以調用效率比 JDK 動態代理通過反射調用更高。5yJ28資訊網——每日最新資訊28at.com

但是我們看上面的源碼也可以明顯看到,JDK動態代理只生成一個文件,而CGLIB生成了三個文件,所以生成代理對象的過程會更復雜。5yJ28資訊網——每日最新資訊28at.com

兩者區別

  • JDK代理只能對實現接口的類生成代理;CGLib是針對類實現代理,對指定的類生成一個子類,并覆蓋其中的方法,這種通過繼承類的實現方式,不能代理final修飾的類。
  • JDK代理使用的是反射機制實現aop的動態代理,CGLib代理使用字節碼處理框架ASM,通過修改字節碼生成子類。
  • JDK動態代理機制是委托機制,具體說動態實現接口類,在動態生成的實現類里面委托hanlder去調用原始實現類方法,CGLib則使用的繼承機制,具體說被代理類和代理類是繼承關系,所以代理類是可以賦值給被代理類的,如果被代理類有接口,那么代理類也可以賦值給接口。

本文鏈接:http://www.tebozhan.com/showinfo-26-38516-0.html詳解JDK動態代理和CGLib動態代理

聲明:本網頁內容旨在傳播知識,若有侵權等問題請及時與本網聯系,我們將在第一時間刪除處理。郵件:2376512515@qq.com

上一篇: 手把手教你寫設計方案,你學明白了嗎?

下一篇: 原生CSS嵌套使用,你學明白了嗎?

標簽:
  • 熱門焦點
  • 6月安卓手機性能榜:vivo/iQOO霸占旗艦排行榜前三

    2023年上半年已經正式過去了,我們也迎來了安兔兔V10版本,在新的驍龍8Gen3和天璣9300發布之前,性能榜的榜單大體會以驍龍8Gen2和天璣9200+為主,至于那顆3.36GHz的驍龍8Gen2領先
  • 2023 年的 Node.js 生態系統

    隨著技術的不斷演進和創新,Node.js 在 2023 年達到了一個新的高度。Node.js 擁有一個龐大的生態系統,可以幫助開發人員更快地實現復雜的應用。本文就來看看 Node.js 最新的生
  • 把LangChain跑起來的三個方法

    使用LangChain開發LLM應用時,需要機器進行GLM部署,好多同學第一步就被勸退了,那么如何繞過這個步驟先學習LLM模型的應用,對Langchain進行快速上手?本片講解3個把LangChain跑起來
  • 一文看懂為蘋果Vision Pro開發應用程序

    譯者 | 布加迪審校 | 重樓蘋果的Vision Pro是一款混合現實(MR)頭戴設備。Vision Pro結合了虛擬現實(VR)和增強現實(AR)的沉浸感。其高分辨率顯示屏、先進的傳感器和強大的處理能力
  • K8S | Service服務發現

    一、背景在微服務架構中,這里以開發環境「Dev」為基礎來描述,在K8S集群中通常會開放:路由網關、注冊中心、配置中心等相關服務,可以被集群外部訪問;圖片對于測試「Tes」環境或者
  • 使用AIGC工具提升安全工作效率

    在日常工作中,安全人員可能會涉及各種各樣的安全任務,包括但不限于:開發某些安全工具的插件,滿足自己特定的安全需求;自定義github搜索工具,快速查找所需的安全資料、漏洞poc、exp
  • 慕巖炮轟抖音,百合網今何在?

    來源:價值研究所 作者:Hernanderz&ldquo;難道就因為自己的一個產品牛逼了,從客服到總裁,都不愿意正視自己產品和運營上的問題,選擇逃避了嗎?&rdquo;這一番話,出自百合網聯合創
  • SN570 NVMe SSD固態硬盤 價格與性能兼具

    SN570 NVMe SSD固態硬盤是西部數據發布的最新一代WD Blue系列的固態硬盤,不僅閃存技術更為精進,性能也得到了進一步的躍升。WD Blue SN570 NVMe SSD的包裝外
  • 英特爾Xe HPG游戲顯卡:擁有512EU,單風扇版本

    據10 月 30 日外媒 TheVerge 消息報道,英特爾 Xe HPG Arc Alchemist 的正面實被曝光,不僅擁有 512 EU 版顯卡,還擁有 128EU 的單風扇版本。另外,這款顯卡 PCB
Top