代理模式簡述

目錄

一、主要角色

二、類型劃分

三、靜態代理

示例

缺點

四、動態代理

JDK動態代理

示例

?缺點

CGLib動態代理

導入依賴

示例

五、Spring AOP


????????代理模式是一種結構型設計模式,通過代理對象控制對目標對象的訪問,可在不改變目標對象情況下增強其功能,隱藏實現細節。

一、主要角色

  • Subject(業務接口類):可以是抽象類或接口
  • RealSubject(業務實現類):具體的業務執行,即被代理的對象
  • Proxy(代理類):RealSubject的代理

二、類型劃分

根據代理的創建時期,可分為靜態代理和動態代理

  • 靜態代理:由程序員創建或工具自動生成代理類源代碼并編譯,程序運行前代理類的字節碼文件已經存在;
  • 動態代理:在程序運行時運用反射機制動態創建而成

為方便下面的講解,我們先提前創建業務接口類和業務實現類

//業務接口類
public interface HouseSubject {void rentHouse();
}
//業務實現類(被代理類)
public class RealHouseSubject implements HouseSubject {@Overridepublic void rentHouse() {System.out.println("我是房東,我出租房子");}
}

三、靜態代理

示例
//代理類
public class HouseProxy implements HouseSubject{//中介出售房子前要先有房東的授權private HouseSubject houseSubject;public HouseProxy(HouseSubject houseSubject) {this.houseSubject = houseSubject;}@Overridepublic void rentHouse() {System.out.println("我是中介,我開始代理房東出租房子");houseSubject.rentHouse();System.out.println("我是中介,代理結束");}
}

使用代理類執行

public class Main {public static void main(String[] args) {//創建代理對象HouseSubject subject=new HouseProxy(new RealHouseSubject());subject.rentHouse();}
}

缺點
  • 為每個被代理類編寫代理類,代碼冗余,隨著業務的發展,類數量膨脹,項目管理難度增大
  • 被代理類接口變化時,所有相關代理類都需修改,易出錯,可維護性差
  • 只能服務特定被代理類,難以應對新類和多變的額外邏輯需求,缺乏靈活性

四、動態代理

JDK動態代理
示例

自定義JDKInvocationHandler 并重寫invoke(),在invoke()中會調用目標方法,并自定義一些處理邏輯

import lombok.extern.slf4j.Slf4j;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;//實現 InvocationHandler接口可以被代理對象的方法進行功能增強
@Slf4j
public class JDKInvocationHandler implements InvocationHandler {//目標類private Object target;public JDKInvocationHandler(Object target) {this.target = target;}/*** 調用目標方法,并對方法進行增強* @param proxy 代理對象* @param method 代理對象需要實現的方法* @param args method方法所對應的參數*/@Overridepublic Object invoke(Object proxy, Method method, Object[] args) throws Throwable {log.info("JDK動態代理開始");//調用目標函數Object result=method.invoke(target,args);log.info("JDK動態代理結束");return null;}
}

創建代理對象,執行邏輯?

import java.lang.reflect.Proxy;public class Main {public static void main(String[] args) {RealHouseSubject target=new RealHouseSubject();//通過被代理類、被代理類實現的接口、方法調用處理器來創建一個代理類/***  ClassLoader loader 類加載器,用于加載代理對象*  Class<?>[] interfaces 被代理類實現的一些接口(jdk只能代理實現了接口的類)*  java.lang.reflect.InvocationHandler h 實現了InvocationHandler接口的對象*/HouseSubject proxy=(HouseSubject) Proxy.newProxyInstance(target.getClass().getClassLoader(),new Class[]{HouseSubject.class},new JDKInvocationHandler(target));//使用代理類proxy.rentHouse();}
}

?缺點

只能代理實現了接口的類,不能代理普通類

CGLib動態代理

導入依賴
<dependency><groupId>cglib</groupId><artifactId>cglib</artifactId><version>3.3.0</version>
</dependency>
示例
import lombok.extern.slf4j.Slf4j;
import net.sf.cglib.proxy.MethodInterceptor;
import net.sf.cglib.proxy.MethodProxy;
import java.lang.reflect.Method;@Slf4j
public class CGLibMethodInterceptor implements MethodInterceptor {private Object target;public CGLibMethodInterceptor(Object target) {this.target = target;}/**** @param o 被代理的對象* @param method 目標方法* @param objects 方法入參* @param methodProxy 用于調用原始方法* @return* @throws Throwable*/@Overridepublic Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {//代理增強內容System.out.println("CGLib代理開始");//通過反射調用被代理的方法Object retVal=methodProxy.invoke(target,objects);System.out.println("CGLib代理結束");return retVal;}
}
import net.sf.cglib.proxy.Enhancer;public class Main {public static void main(String[] args) {HouseSubject target=new RealHouseSubject();HouseSubject proxy= (HouseSubject)Enhancer.create(target.getClass(),new CGLibMethodInterceptor(target));proxy.rentHouse();}
}

五、Spring AOP

Spring AOP是基于動態代理實現的,動態代理有JDK和CGLIB兩種方式,運行時使用哪種方式與項目配置和代理的對象有關。

proxy-target-class="false"情況下,若代理對象實現接口,默認使用JDK動態代理;若未實現接口,則會用CGLIB動態代理。當然,即便對象實現接口,也能通過xml配置proxy-target-class="true"或在配置類上使用注解@EnableAspectJAutoProxy(proxyTargetClass = true) 強制使用CGLIB動態代理。

Spring Boot 2.X開始默認使用CGLIB代理,也就是proxy-target-class="true"。

二者各有優劣,需依項目實際情況抉擇。JDK動態代理優勢在于基于Java原生支持,無需額外依賴,性能較好,適用于對性能要求高且目標對象有接口的場景;但是只能代理實現了接口的對象。

CGLIB動態代理優勢在于能代理無接口的普通類,功能更強大、靈活性更高;但是需額外注入依賴,且通過繼承創建代理,若類被final修飾則無法代理,生成代理對象的性能開銷相對較大。

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

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

相關文章

每日一題——云服務計費問題

云服務計費問題&#xff08;哈希表 排序&#xff09;| 附詳細 C源碼解析 一、題目描述二、輸入描述三、輸出描述四、樣例輸入輸出輸入示例&#xff1a;輸出示例&#xff1a;說明&#xff1a; 五、解題思路分析六、C實現源碼詳解&#xff08;完整&#xff09;七、復雜度分析 一…

【JVM】運行時數據區域

文章目錄 1. 程序計數器補充 2. 虛擬機棧2.1 棧幀1. 局部變量表2. 操作數棧3. 動態鏈接4. 方法返回地址補充 3. 本地方法棧4. 堆5. 方法區靜態常量池&#xff08;Class常量池&#xff09;運行時常量池字符串常量池&#xff08;1&#xff09;位置變化&#xff08;2&#xff09;放…

day28圖像處理OpenCV

文章目錄 一、圖像預處理4 邊緣填充4.1 邊界復制&#xff08;BORDER_REPLICATE&#xff09;4.2 邊界反射&#xff08;BORDER_REFLECT&#xff09;4.3 邊界反射101&#xff08;BORDER_REFLECT_101&#xff09;4.4 邊界常數&#xff08;BORDER_CONSTANT&#xff09;4.5 邊界包裹&…

C++ Json-Rpc框架-3項目實現(2)

一.消息分發Dispatcher實現 Dispatcher 就是“消息分發中樞”&#xff1a;根據消息類型 MType&#xff0c;把消息派發給對應的處理函數&#xff08;Handler&#xff09;執行。 初版&#xff1a; #pragma once #include "net.hpp" #include "message.hpp"n…

C++算法優化實戰:破解性能瓶頸,提升程序效率

C算法優化實戰&#xff1a;破解性能瓶頸&#xff0c;提升程序效率 在現代軟件開發中&#xff0c;算法優化是提升程序性能的關鍵手段之一。無論是在高頻交易系統、實時游戲引擎&#xff0c;還是大數據處理平臺&#xff0c;算法的高效性直接關系到整體系統的性能與響應速度。C作…

【PostgreSQL教程】PostgreSQL 特別篇之 語言接口連接PHP

博主介紹:?全網粉絲22W+,CSDN博客專家、Java領域優質創作者,掘金/華為云/阿里云/InfoQ等平臺優質作者、專注于Java技術領域? 技術范圍:SpringBoot、SpringCloud、Vue、SSM、HTML、Nodejs、Python、MySQL、PostgreSQL、大數據、物聯網、機器學習等設計與開發。 感興趣的可…

山東大學軟件學院創新項目實訓開發日志(12)之將對話記錄保存到數據庫中

在之前的功能開發中&#xff0c;已經成功將deepseekAPI接口接入到springbootvue項目中&#xff0c;所以下一步的操作是將對話和消息記錄保存到數據庫中 在之前的開發日志中提到數據庫建表&#xff0c;所以在此刻需要用到兩個表&#xff0c;conversation表和message表&#xff…

Spring-注解編程

注解基礎概念 1.什么是注解編程 指的是在類或者方法上加入特定的注解(XXX) 完成特定功能的開發 Component public classXXX{} 2.為什么要講注解編程 1.注解開發方便 代碼簡潔 開發速度大大提高 2.Spring開發潮流 Spring2.x引入注解 Spring3.x完善注解 Springboot普及 推廣注解…

Dify智能體平臺源碼二次開發筆記(5) - 多租戶的SAAS版實現(2)

目錄 前言 用戶的查詢 controller層 添加路由 service層 用戶的添加 controller層 添加路由 service層-添加用戶 service層-添加用戶和租戶關系 驗證結果 結果 前言 完成租戶添加功能后&#xff0c;下一步需要實現租戶下的用戶管理。基礎功能包括&#xff1a;查詢租…

基于若依的ruoyi-vue-plus的nbmade-boot在線表單的設計(一)架構方面的設計

希望大家一起能參與我的新開源項目nbmade-boot: 寧波智能制造低代碼實訓平臺 主要目標是類似設計jeecgboot那樣的online表單功能,因為online本身沒有開源這部分代碼,而我設計這個是完全開源的,所以希望大家支持支持,開源不容易。 1、數據庫方面設計考慮 是在原來gen_table和…

WebFlux應用中獲取x-www-form-urlencoded數據的六種方法

&#x1f9d1; 博主簡介&#xff1a;CSDN博客專家&#xff0c;歷代文學網&#xff08;PC端可以訪問&#xff1a;https://literature.sinhy.com/#/?__c1000&#xff0c;移動端可微信小程序搜索“歷代文學”&#xff09;總架構師&#xff0c;15年工作經驗&#xff0c;精通Java編…

[Python基礎速成]1-Python規范與核心語法

本系列旨在快速掌握Python&#xff0c;實現能夠快速閱讀和理解 Python 代碼&#xff0c;并在可查閱語法的情況下進行 AI 學習。 本篇先了解一下Python基礎知識。 本篇內容較菜鳥教程有所刪減、方便快速構建大綱&#xff0c;且加入了PEP 8規范說明等有助于理解和編寫代碼的說明。…

農民劇團的春天與改變之路

楊天義&#xff0c;男&#xff0c;1966年9月生&#xff0c;中共黨員&#xff0c;江西省吉安市吉水縣水南農民劇團團長。 楊天義從廢品收購起家&#xff0c;憑借自身的努力和奮斗&#xff0c;自籌資金100余萬元建設了水南鎮的第一座影劇院&#xff0c;組建了江西省吉安市吉水縣…

python asyncio 的基本使用

1、引言 asyncio 是 Python 標準庫中的一個庫&#xff0c;提供了對異步 I/O 、事件循環、協程和任務等異步編程模型的支持。 asyncio 文檔 2、進程、線程、協程 線程 線程是操作系統調度的基本單位&#xff0c;同一個進程中的多個線程共享相同的內存空間。線程之間的切換由操…

Leedcode刷題 | Day30_貪心算法04

一、學習任務 452. 用最少數量的箭引爆氣球代碼隨想錄435. 無重疊區間763. 劃分字母區間 二、具體題目 1.452用最少數量的箭引爆氣球452. 用最少數量的箭引爆氣球 - 力扣&#xff08;LeetCode&#xff09; 在二維空間中有許多球形的氣球。對于每個氣球&#xff0c;提供的輸…

Ant Design Vue 表格復雜數據合并單元格

Ant Design Vue 表格復雜數據合并單元格 官方合并效果 官方示例 表頭只支持列合并&#xff0c;使用 column 里的 colSpan 進行設置。 表格支持行/列合并&#xff0c;使用 render 里的單元格屬性 colSpan 或者 rowSpan 設值為 0 時&#xff0c;設置的表格不會渲染。 <temp…

C++ 標準庫中的 <algorithm> 頭文件算法總結

C 常用 <algorithm> 算法概覽 C 標準庫中的 <algorithm> 頭文件提供了大量有用的算法&#xff0c;主要用于操作容器&#xff08;如 vector, list, array 等&#xff09;。這些算法通常通過迭代器來操作容器元素。 1. 非修改序列操作 std::all_of, std::any_of, s…

程序化廣告行業(84/89):4A廣告代理公司與行業資質解讀

程序化廣告行業&#xff08;84/89&#xff09;&#xff1a;4A廣告代理公司與行業資質解讀 大家好&#xff01;在探索程序化廣告行業的道路上&#xff0c;每一次知識的分享都是我們共同進步的階梯。一直以來&#xff0c;我都希望能和大家攜手前行&#xff0c;深入了解這個充滿機…

deepin使用autokey添加微信快捷鍵一鍵顯隱ctrl+alt+w

打開deepin商店&#xff0c;搜索快捷鍵&#xff0c;找到autokey 快捷鍵管理&#xff0c;點擊安裝 點擊右鍵新建文件夾 點擊右鍵新建腳本 打開腳本并添加以下內容 import subprocess import time# ------------------ 配置項 ------------------ WM_CLASS "wechat…

文件內容課堂總結

Spark SQL是Spark用于結構化數據處理的模塊&#xff0c;前身是Shark。Shark基于Hive開發&#xff0c;雖提升了SQL-on-Hadoop效率&#xff0c;但對Hive依賴過多。2014年6月1日Shark項目停止開發&#xff0c;團隊將資源投入Spark SQL項目。Spark SQL具有諸多優點&#xff0c;如擺…