代理模式(Java實現)

代理模式是常見的設計模式之一,顧名思義,代理模式就是代理對象具備真實對象的功能,并代替真實對象完成相應操作,并能夠在操作執行的前后,對操作進行增強處理。(為真實對象提供代理,然后供其他對象通過代理訪問真實對象)

分為

  • 靜態代理

  • 動態代理

    • jdk動態代理

    • cglib動態代理

靜態代理

真實類和代理類要實現同一個接口,在代理類中實現真實類的方法同時可以進行真實類方法的增強處理,在一個代理類中就可以完成對多個真實對象的注入工作。

public interface IRentHouse {void rentHouse();
}
public class RentHouse implements IRentHouse {@Overridepublic void rentHouse() {System.out.println("實現租房");}
}
public class IntermediaryProxy implements IRentHouse {private IRentHouse iRent;public IntermediaryProxy(IRentHouse iRentHouse) {iRent=iRentHouse;}@Overridepublic void rentHouse() {System.out.println("交中介費");iRent.rentHouse();System.out.println("中介負責維修管理");}
}
//client測試類
public class TestStaticProxy {public static void main(String[] args) {//定義租房IRentHouse iRentHouse = new RentHouse();//定義中介IRentHouse intermediaryProxy = new IntermediaryProxy(iRentHouse);//中介租房intermediaryProxy.rentHouse();}
}

動態代理

從靜態代理的代碼中可以發現,靜態代理的缺點顯而易見,那就是當真實類的方法越來越多的時候,這樣構建的代理類的代碼量是非常大的,所以就引進動態代理.

動態代理允許使用一種方法的單個類(代理類)為具有任意數量方法的任意類(真實類)的多個方法調用提供服務

JAVA 反射機制是在運行狀態中,對于任意一個類,都能夠知道這個類的所有屬性和方法;對于任意一個對象,都能夠調用它的任意一個方法和屬性;這種動態獲取的信息以及動態調用對象的方法的功能稱為 java 語言的反射機制。

jdk動態代理(接口代理)

Jdk代理涉及到java.lang.reflect包中的InvocationHandler接口和Proxy類,核心方法是

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

jdk動態代理過程中實際上代理的是接口,是因為在創建代理實例的時候,依賴的是java.lang.reflect包中Proxy類的newProxyInstance方法,該方法的生效就恰恰需要這個參數;

public static Object newProxyInstance(ClassLoader loader,Class<?>[] interfaces,InvocationHandler h) throws IllegalArgumentException{……
}

下面以案例來說明jdk動態代理的完整過程:

//接口
public interface Person {void wakeup();void sleep();
}
//實現類1
public class Student implements Person{private String name;public Student() {}public Student(String name) {this.name = name;}@Overridepublic void wakeup() {System.out.println("學生"+name+"早晨醒來啦");}@Overridepublic void sleep() {System.out.println("學生"+name+"晚上睡覺啦");}
}
//代理類
public class JDKDynamicProxy implements InvocationHandler {private Object bean;public JDKDynamicProxy(Object bean) {this.bean=bean;}@Overridepublic Object invoke(Object proxy, Method method, Object[] args) throws Throwable {String methodname=method.getName();if (methodname.equals("wakeup")){System.out.println("早安~~~");}else if(methodname.equals("sleep")){System.out.println("晚安~~~");}return method.invoke(bean,args);}
}
//測試類
public class TestJDKDynamicProxy {public static void main(String[] args) {JDKDynamicProxy proxy = new JDKDynamicProxy(new Student("張三"));//創建代理實例Person student = (Person) Proxy.newProxyInstance(proxy.getClass().getClassLoader(), new Class[]{Person.class}, proxy);student.wakeup();student.sleep();}
}

輸出結果為

早安~~
學生張三早晨醒來啦
晚安~~
學生張三晚上睡覺啦
接口中的方法,以及代理類中重寫的invoke方法,但是invoke()方法并不是顯式調用的,是在創建代理實例的過程中生成的接口虛擬代理類中調用了invoke方法。(把Sproxy0的實例強制轉換成對應接口類型的引用,然后執行接口方法,進而執行代理類中invoke ()) 

總結對比:

1.靜態代理中,代理類和真實類實現的是同一個接口,重寫同樣的方法;jdk動態代理中,代理類和真實類關系不大,代理類實現無侵入式的代碼擴展。

2.靜態代理中當接口中方法增加的時候,在代理類代碼量也會增加,顯然是不妥的;jdk動態代理解決了這個問題,當業務增加,代理類的代碼不會增加。

3.jdk動態代理實現的是jdk自帶InvocationHandler接口,實現了這個接口的類也叫攔截器類,也叫代理類。

cglib動態代理

從上面可以看出,jdk動態代理的前提條件是,要有接口存在,那還有許多場景是沒有接口的,這個時候就需要cglib動態代理了,CGLIB(Code Generation Library)是一個基于ASM的字節碼生成庫,它允許我們在運行時對字節碼進行修改和動態生成。CGLIB通過繼承方式實現代理。cglib動態代理過程中生成的是實現類的子類,cglib是如何憑空創造的實現類的子類的,下面是測試代碼

//所需的代理類
public class CglibProxy implements MethodInterceptor {private Enhancer enhancer=new Enhancer();private Object bean;public CglibProxy(Object bean) {this.bean = bean;}public Object getProxy(){//設置需要創建子類的類enhancer.setSuperclass(bean.getClass());enhancer.setCallback(this);return enhancer.create();}@Overridepublic Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {String methodName = method.getName();if (methodName.equals("wakeup")){System.out.println("早安~~~");}else if(methodName.equals("sleep")){System.out.println("晚安~~~");}return method.invoke(bean,objects);}
}
//測試類
public class TestCglibProxy {public static void main(String[] args) {//生成虛擬代理類的代碼,本來虛擬代理子類是看不見的,//下面這句話的作用就是把執行過程中cglib增強后的class字節碼文件System.setProperty(DebuggingClassWriter.DEBUG_LOCATION_PROPERTY, "D:\\aop");CglibProxy proxy = new CglibProxy(new Cat("咪咪"));Cat cat = (Cat) proxy.getProxy();cat.wakeup();cat.sleep();}
}

總結:

cglib動態代理和jdk動態代理的區別顯而易見,但是實現邏輯差不多,cglib代理類是通過實現MethodInterceptor,重寫intercept方法,通過生成被代理類的子類來達到代理增強代碼的目的;而Jdk代理是通過實現InvocationHandler,重寫invoke方法,通過生成接口的代理類來達到代碼增強的目的,所以jdk動態代理的實現需要接口,cglib則不需要,spring5.0以上以及springboot2.0以上默認采用cglib動態來實現AOP。

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/news/38468.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/38468.shtml
英文地址,請注明出處:http://en.pswp.cn/news/38468.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

threejs使用gui改變相機的參數

調節相機遠近角度 定義相機的配置&#xff1a; const cameraConfg reactive({ fov: 45 }) gui中加入調節fov的方法 const gui new dat.GUI();const cameraFolder gui.addFolder("相機屬性設置");cameraFolder.add(cameraConfg, "fov", 0, 100).name(…

YOLO格式數據集(.txt)如何轉換為VOC格式數據集(.xml)

前言&#xff1a; 安裝好python環境與編譯器 轉換&#xff1a; 將標注文件從文本格式&#xff08;.txt&#xff09;轉換為 XML 格式&#xff08;.xml&#xff09;可以通過以下步驟完成&#xff1a; 解析文本標注文件&#xff1a;打開 .txt 文件&#xff0c;逐行讀取每個標注…

Gin模板語法

Gin模板語法 文章目錄 <center> Gin模板語法前提提醒Gin框架啟動服務器模板解析模板渲染遇到不同目錄下相同的文件如何加載和渲染自定義函數加載靜態文件 前提提醒 由于有了前面template包的基礎,所以該筆記不再過多詳細分析 Gin框架啟動服務器 語法: r:gin.Default()/…

Medical Isolated Power Supply System in Angola

安科瑞 華楠 Abstract: Diagnosis and treatment in modern hospitals are inseparable from advanced medical equipment, which are inseparable from safe and reliable power supply. Many operations often last for several hours, and the consequences of a sudden pow…

【UE4 RTS】07-Camera Boundaries

前言 本篇實現的效果是當CameraPawn移動到地圖邊緣時會被阻擋。 效果 步驟 1. 打開項目設置&#xff0c;在“引擎-碰撞”中&#xff0c;點擊“新建Object通道” 新建通道命名為“MapBoundaries”&#xff0c;然后點擊接受 2. 向視口中添加 阻擋體積 調整阻擋體積的縮放 向四…

【TypeScript】this指向,this內置組件

this類型 TypeScript可推導的this類型函數中this默認類型對象中的函數中的this明確this指向 怎么指定this類型 this相關的內置工具類型轉換ThisParameterType<>ThisParameterType<>ThisType TypeScript可推導的this類型 函數中this默認類型 對象中的函數中的this…

華為OD機試-字符串序列判定

題目描述 給定兩個字符串 s和 t &#xff0c;判斷 s是否為 t 的子序列。 你可以認為 s 和 t 中僅包含英文小寫字母。字符串 t 可能會很長&#xff08;長度n ~ 500,000&#xff09;&#xff0c;而 s 是個短字符串&#xff08;長度 <100&#xff09;。字符串的一個子序列是原…

Docker容器:docker基礎及安裝

文章目錄 一.docker容器概述1.什么是容器2. docker與虛擬機的區別2.1 docker虛擬化產品有哪些及其對比2.2 Docker與虛擬機的區別 3.Docker容器的使用場景4.Docker容器的優點5.Docker 的底層運行原理6.namespace的六項隔離7.Docker核心概念 二.Docker安裝 及管理1.安裝 Docker1.…

【科研論文配圖繪制】task1 掌握科研繪圖的基本知識

【科研論文配圖繪制】task1 掌握科研繪圖的基本知識 寫在最前 8月份Datawhale組隊學習&#xff0c;寫下該博客記錄學習內容 1.科研論文配圖的分類與構成 2.科研論文配圖的格式和尺寸 3.科研論文配圖中的字體和字號設置 4.科研論文配圖的版式設計、結構布局和顏色搭配 占個…

機器學習筆記 - 基于C++的??深度學習 三、實現成本函數

機器學習中的建模 作為人工智能工程師,我們通常將每個任務或問題定義為一個函數。 例如,如果我們正在開發面部識別系統,我們的第一步是將問題定義為將輸入圖像映射到標識符的函數F(X)。但是問題是如何知道F(X)公式? 事實上,使用公式或一系列固有規則來定義F(X)是不可行的(…

【Go 基礎篇】Go語言指針解析:深入理解內存與引用的奧秘

介紹 指針是計算機編程中的重要概念&#xff0c;它提供了直接訪問內存地址的能力&#xff0c;為程序的數據處理和內存管理提供了靈活性和效率。在Go語言&#xff08;Golang&#xff09;中&#xff0c;指針也是一種重要的數據類型&#xff0c;用于處理變量的引用和修改。本篇博…

GraphQL(六)登錄態校驗Directive

GraphQL Directive&#xff08;指令&#xff09;是GraphQL中的一種特殊類型&#xff0c;它允許開發者在GraphQL schema中添加元數據&#xff0c;以控制查詢和解析操作的行為 Directive的詳細說明及使用可見GraphQL&#xff08;五&#xff09;指令[Directive]詳解 本文將介紹通過…

勘探開發人工智能技術:機器學習(6)

0 提綱 7.1 循環神經網絡RNN 7.2 LSTM 7.3 Transformer 7.4 U-Net 1 循環神經網絡RNN 把上一時刻的輸出作為下一時刻的輸入之一. 1.1 全連接神經網絡的缺點 現在的任務是要利用如下語料來給apple打標簽&#xff1a; 第一句話&#xff1a;I like eating apple!(我喜歡吃蘋…

06 json數據解析和列表控件

內容回顧 json數據解析 json ----- 對要傳輸的數據進行封裝的工具 json是由json數組([]) 和 json對象({})在qt中,對JSON數據進行處理(解析和打包) JSON數據處理所要包含的類: QJsonDocument -----它的作用是將數據轉換成json文檔 QJsonArray ---- json數組,就是封裝多個…

User-Agent介紹

User-Agent介紹 引言 在Web開發中&#xff0c;我們經常會遇到需要根據不同的用戶設備或瀏覽器類型來進行特定處理的情況。為了達到這樣的目的&#xff0c;我們可以使用User-Agent這個HTTP頭信息字段來識別用戶的設備和瀏覽器。本篇文章將介紹User-Agent的基本概念、用法以及在…

SpringBoot 學習(02): 從嵌入式系統到嵌入式Servlet SpingBoot 的進化之路

嵌入式系統 計算機操作系統啟動后&#xff0c;會加載一系列的功能和服務&#xff0c;而這些東西都不是開發操作系統的人寫的&#xff0c;如果想讓一個生態快速崛起&#xff0c;那么操作系統的開發人&#xff0c;就要告訴大家&#xff0c;在這個操作系統上&#xff0c;你要遵守…

3.1 Ansible 的使用和配置管理

Ansible 的使用和配置管理 文章目錄 Ansible 的使用和配置管理Ansible 基礎Ansible 模塊和變量主機管理和組織角色和劇本部署應用和配置自動化與批量操作Ansible 常見用例Ansible 最佳實踐和性能優化 大綱 Ansible 簡介和特點 介紹 Ansible 的定義和作用&#xff0c;以及它在配…

【Java】Guava的Striped類。

Striped類,它提供了一種線程安全的分段鎖(Striped Locking)機制。 Striped類可以用于將一組資源或操作分成多個段(Stripes),每個段上都有一個獨立的鎖。這種機制可以在并發訪問時提供更好的性能,因為不同線程可以同時訪問不同的段而不會相互阻塞。通常,Striped鎖適用于…

pytorch3d成功安裝

一、pytorch3d是什么&#xff1f; PyTorch3D的目標是幫助加速深度學習和3D交叉點的研究。3D數據比2D圖像更復雜&#xff0c;在從事Mesh R-CNN和C3DPO等項目時&#xff0c;我們遇到了一些挑戰&#xff0c;包括3D數據表示、批處理和速度。我們開發了許多有用的算子和抽象&#xf…

【Visual Studio Code】--- Win11 安裝 VS Code 超詳細

Win11 安裝 VS Code 超詳細 概述一、下載 Vscode二、安裝 Vscode 概述 一個好的文章能夠幫助開發者完成更便捷、更快速的開發。書山有路勤為徑&#xff0c;學海無涯苦作舟。我是秋知葉i、期望每一個閱讀了我的文章的開發者都能夠有所成長。 一、下載 Vscode Vscode官網 二、…