12、设计模式之代理模式(Proxy)
一、什么是代理模式
代理模式属于结构型设计模式。为其他对象提供一种代理以控制对这个对象的访问。
在某些情况下,一个对象不适合或者不能直接引用另一个对象,而代理对象可以在客户端和目标对象之间起到中介的作用。
二、分类
代理模式分为三类:
- 静态代理
- 动态代理
- CGLIB代理
三、特点
优点:
代理模式可以隐藏真是对象的实现细节,使客户端无需知晓真实对象的工作方式和结构。
通过代理类来间接访问真实类,可以在不修改真实类的情况下,对其进行扩展、优化或添加安全措施。
代理模式实现起来简单,易于扩展和维护,符合面向对象设计原则中的开闭原则。
缺点:
代理模式可能会引入额外的复杂性和间接性,增加程序设计和维护的难度。
对象代理可能会降低系统性能,特别是在处理大数据量或频繁调用的情况下,因为代理需要额外的计算和网络通信开销。
四、应用场景
4.1 生活场景
Window是的快捷键。
支票、银行卡。
律师。
4.2 Java场景
AOP:通过定义切面、切入点和通知等,Spring
AOP在运行时生成代理对象,将切面逻辑织入到目标对象的方法调用中。代理对象在方法调用前后执行附加操作,如日志记录、性能监控等。
动态代理(JDK动态代理、CGLIB代理):当Bean类实现了接口时,Spring使用JDK动态代理来为Bean生成代理对象;当Bean类没有实现接口时,Spring使用CGLIB代理来生成代理对象。
五、代码实现
5.0 代码结构

下面就以房东和租客为例,分别介绍一下静态代理、jdk动态代理和cglib代理。
5.1 静态代理
静态代理是一种在代码编写期进行代理类和被代理类的关联的代理方式。
具体实现是创建一个代理类,通常需要实现与被代理类相同的接口或继承被代理类。

房东接口类:Landlord1Service,
注意:静态代理实现它的真实对象只能有一个,多个的话,代理对象不能确定哪个对象需要被代理,会导致报错,JDK动态代理没这个问题
/*** 房东* */
public interface Landlord1Service {/*** 出租* @param money 金额* @return*/void rent(Integer money);
}
租客:TenantImpl/*** 租客* @author Created by njy on 2023/5/30*/
@Component
public class TenantImpl implements Landlord1Service {@Overridepublic void rent(Integer money) {System.out.println("租下"+money+"元一个月的房子");}
}
静态代理:ProxyImpl
/*** 中介* */
@Component
public class ProxyImpl implements Landlord1Service {/*** 房东有很多套房子,不想亲自出马了,于是找来了中介*/@Autowiredprivate Landlord1Service target;/*** 优点就是在不改变原来的实现类的情况下对方法实现了增强* 缺点是如果原来的接口新增了方法,那么这里也要对应实现新的方法* @param money 金额* @return*/@Overridepublic void rent(Integer money) {System.out.println("[静态代理]交中介费");target.rent(money);System.out.println("[静态代理]中介负责维修管理");}
}
测试:
@SpringBootTest
public class TestProxy {@Autowiredprivate TenantImpl tenant;@Autowiredprivate ProxyImpl proxy;//1.静态代理@Testvoid TestStatic(){tenant.rent(1000);System.out.println();proxy.rent(2000);}
}
适用场景:
对象必须实现一个或多个接口
代理类的代理方法不需要额外的逻辑
5.2 JDK动态代理
JDK动态代理是一种比较常见的代理方式,它是在程序运行时动态生成代理类,也就是说我们在编写代码时并不知道具体代理的是什么类,而是在程序运行时动态生成。

房东接口类:Landlord2Service
public interface Landlord2Service {/*** 出租* @param money* @return*/void rent(Integer money);
}
租客1:Teant1Impl
@Component
public class Teant1Impl implements Landlord2Service{@Overridepublic void rent(Integer money) {System.out.println("tenant1租下"+money+"元一个月的房子");}
}
租客2:Teant2Impl
@Component
public class Tenant2Impl implements Landlord2Service {@Overridepublic void rent(Integer money) {System.out.println("tenant2租下"+money+"元一个月的房子");}
}
JDK动态代理:JDKProxy
/*** JDK动态代理:就是把代理抽象了一下* */
public class JDKProxy {private Object target;public JDKProxy(Object target){this.target=target;}/*** 给目标对象生成代理对象* @return 代理生成的对象*/public Object getProxyInstance(){return Proxy.newProxyInstance(target.getClass().getClassLoader(),target.getClass().getInterfaces(),//这里是要实现jdk代理InvocationHandler的接口,lambda表达式(proxy,method,args)->{//执行对象方法System.out.println("[JDK动态代理]交中介费");method.invoke(target,args);System.out.println("[JDK动态代理]中介负责维修管理");return null;});}
}
Test:
@SpringBootTest
public class TestProxy {@Autowiredprivate Teant1Impl teant1;@Autowiredprivate Tenant2Impl tenant2;//2.JDK动态代理@Testvoid TestJDK(){Landlord2Service proxyInstance1 = (Landlord2Service) new JDKProxy(teant1).getProxyInstance();proxyInstance1.rent(2500);System.out.println();Landlord2Service proxyInstance2 = (Landlord2Service) new JDKProxy(tenant2).getProxyInstance();proxyInstance2.rent(2500);}
}
适用场景:
对象必须实现一个或多个接口
代理类的代理方法不需要额外的逻辑
5.3 Cglib代理
CGLIB代理是在运行时动态生成代理类的方式,它使用的库是cglib,和JDK代理相比,它不是动态的生成一个实现了接口的代理类,而是直接在内存中构建一个被代理类的子类,并重写父类的方法来进行代理。

房东类:Landlord3Service
@Component
public class Landlord3Service {/*** 出租房屋* @param money* @return*/public void rent(Integer money){System.out.println("租下"+money+"元一个月的房子");}
}
Cglib代理类:CglibProxy
/*** JDKProxy:cglib子类代理工厂* 1.代理的类不能为final* 2.目标对象的方法如果为final/static,那么就不会被拦截,也不会执行目标对象的业务方法* */
public class CglibProxy implements MethodInterceptor {/*** 目标对象*/private final Object target;public CglibProxy(Object target){this.target=target;}public Object getProxyInstance(){//1.工具类Enhancer en=new Enhancer();//2.设置父类en.setSuperclass(target.getClass());//3.设置回调函数en.setCallback(this);//4.创建子类(代理对象)return en.create();}@Overridepublic Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {System.out.println("[Cglib代理]交中介费");method.invoke(target,objects);System.out.println("[Cglib代理]中介负责维修管理");return null;}
}
测试:
@SpringBootTest
@RequiredArgsConstructor
public class TestProxy {@Autowiredprivate Landlord3Service landlord3Service;//3.Cglib代理@Testvoid TestCglib(){Landlord3Service proxyInstance = (Landlord3Service) new CglibProxy(landlord3Service).getProxyInstance();proxyInstance.rent(3000);}
}
适用场景:
被代理的类没有实现接口或者无法实现接口
代理类的代理方法需要进行额外的逻辑,如事务处理等。
六、总结
对于没有实现接口的类,只能使用CGLIB代理
对于实现了接口的类,可以使用JDK代理或者CGLIB代理,如果要求比较高的话,建议使用JDK代理。
对于单个代理类的情况,并且被代理类实现了接口,可以使用静态代理。
对于多个被代理类的情况,建议使用JDK代理或CGLIB代理。
相关文章:
12、设计模式之代理模式(Proxy)
一、什么是代理模式 代理模式属于结构型设计模式。为其他对象提供一种代理以控制对这个对象的访问。 在某些情况下,一个对象不适合或者不能直接引用另一个对象,而代理对象可以在客户端和目标对象之间起到中介的作用。 二、分类 代理模式分为三类&#…...
springboot集成Quartz定时任务组件
文章目录 前言一、Quartz 是什么?下面是对 Java 中 Quartz 的主要概念的简单描述: 二、使用步骤总结 前言 平时开发中相信大家都经常用到定时任务吧,最近简单的就是直接使用Scheduled注解标注到方法上用注解的方式在项目运行时无法去对任务进…...
代码随想录算法训练营第38天—动态规划06 | ● 完全背包 ● *518. 零钱兑换 II ● 377. 组合总和 Ⅳ
完全背包 视频讲解:https://www.bilibili.com/video/BV1uK411o7c9 https://programmercarl.com/%E8%83%8C%E5%8C%85%E9%97%AE%E9%A2%98%E7%90%86%E8%AE%BA%E5%9F%BA%E7%A1%80%E5%AE%8C%E5%85%A8%E8%83%8C%E5%8C%85.html 题目描述:有n件物品和一个最多能…...
C语言每日一题(63)复写零
题目链接 力扣网 1089 复写零 题目描述 给你一个长度固定的整数数组 arr ,请你将该数组中出现的每个零都复写一遍,并将其余的元素向右平移。 注意:请不要在超过该数组长度的位置写入元素。请对输入的数组 就地 进行上述修改,不…...
ElasticSearch聚合查询
数据准备 索引创建 PUT product {"mappings": {"properties": {"createtime": {"type": "date"},"desc": {"type": "text","fields": {"keyword": {"type": …...
【毕设级项目】基于AI技术的多功能消防机器人(完整工程资料源码)
基于AI技术的多功能消防机器人演示效果 竞赛-基于AI技术的多功能消防机器人视频演示 前言: 随着“自动化、智能化”成为数字时代发展的关键词,机器人逐步成为社会经济发展的重要主体之一,“机器换人”成为发展的全新趋势和时代潮流。在可预见…...
【一】【设计模式】类关系UML图
1. 继承(Generalization) 继承是对象间的一种层次关系,允许子类继承并扩展父类的功能。 UML线:带有空心箭头的直线,箭头指向基类(父类)。 class Parent {public void parentMethod() {System.…...
【DevOps基础篇】容器化架构基础设施监控方案
【DevOps基础篇】容器化架构基础设施监控方案 目录 【DevOps基础篇】容器化架构基础设施监控方案要监视什么不同监控系统方案比较1. Datadog2. Prometheus3. ELK(Elasticsearch、Logstash、Kibana)4. Sysdig5. 自行打造!如何选择总结推荐超级课程: Docker快速入门到精通 当…...
【QT】文件流操作(QTextStream/QDataStream)
文本流/数据流(二级制格式) 文本流 (依赖平台,不同平台可能乱码)涉及文件编码 #include <QTextStream>操作的都是基础数据类型:int float string //Image Qpoint QRect就不可以操作 需要下面的 …...
CentOS 7 devtoolset编译addressSanitizer版本失败的问题解决
在我的一个Cent OS7开发环境中,按https://yeyongjin.blog.csdn.net/article/details/134178420的方法升级GCC版本到8.3.1。 这两天,要用Google的addressSanitizer检验内存问题,加上编译参数后,却发现编译不通过。configure时直接退…...
ubuntu2004桌面系统英伟达显卡驱动安装方法
#如何查看显卡型号 lspci | grep -i vga#----output------ 01:00.0 VGA compatible controller: NVIDIA Corporation Device 1f06 (rev a1)根据 Device 后的 值 进入网站查询 pci-ids.ucw.cz/mods/PC/10de?actionhelp?helppci #根据显卡型号,下载对应系统的驱动…...
Java通过Excel批量上传数据!!!
一、首先在前端写一个上传功能。 <template><!-- 文件上传 --><el-upload class"upload-demo" drag action"" :on-change"onChange" :auto-upload"false"><el-icon class"el-icon--upload"><up…...
【PyQT/Pysider】控件背景渐变
默认渐变配色说明 background-color: qlineargradient(spread:pad, x1:0, y1:0, x2:1, y2:0, stop:0 rgba(255, 178, 102, 255), stop:0.55 rgba(235, 148, 61, 255), stop:0.98 rgba(0, 0, 0, 255), stop:1 rgba(0, 0, 0, 0));这段样式表使用了qlineargradient函数来创建…...
ChatGPT-4 VS 文心一言4.0
在线体验 地址(含 gpt 3.5 / 4.0,文心 3.5 / 4.0):https://chat.tool4j.com 点击访问 文心一言和ChatGPT-4都是非常强大的自然语言处理模型,它们都能够在对话系统和其他NLP应用中发挥巨大的作用。然而,它们…...
MYSQL------从概述到DQL
数据库(数据管理,数据存储的仓库) 数据库管理系统(操纵和管理数据库的大型软件) SQL是操作关系型的编程语言,是一套标准 MySQL下载安装完成以后,可以进行启动和停止操作,对于启动和停…...
MATLAB算法实战应用案例精讲-【图像处理】图像识别(基础篇)(二)
目录 数字图像处理基本知识 传统图像处理方法进行瑕疵检测 传统算法方向的选择...
Leetcode 3.12
leetcode hot 100 链表1.两两交换链表中的节点2.随机链表的复制3.排序链表 链表 1.两两交换链表中的节点 两两交换链表中的节点 1.必须要设置一个dummy (temp) 结点2.保存第二个节点3.先让第一个节点指向第三个节点4.再让第二个节点指向第一个节点5.最后让dummy指向第二个节点…...
【天池课堂】零基础入门数据挖掘-课程汇总
写在前面: 如果你现在很迷茫,但是又对数据挖掘感兴趣,建议先看看以下两个视频直播,两位大佬亲身讲述自己和数据挖掘的前世今生。 《如何入门数据挖掘竞赛》 鱼遇雨欲语与余。天池明星选手,武汉大学硕士,天…...
表单进阶(3)-上传文件和隐藏字段
上传文件:<input type"file"> 隐藏字段:<input type"hidden" name"" id"" value"带给后端的信息"> 禁用disabled:<button disabled"disabled">注册</bu…...
LLM(大语言模型)常用评测指标-MAP@R
MAPR (Mean Average Precision at R) 是一种用于评估信息检索系统或排序模型效果的评价指标。它特别适用于那些返回一组相关结果的情况,例如搜索引擎或推荐系统。这里的“R”代表返回的相关结果的数量。MAPR 考虑了结果的排名和相关性两个因素。 计算方法 计算平…...
Debian系统简介
目录 Debian系统介绍 Debian版本介绍 Debian软件源介绍 软件包管理工具dpkg dpkg核心指令详解 安装软件包 卸载软件包 查询软件包状态 验证软件包完整性 手动处理依赖关系 dpkg vs apt Debian系统介绍 Debian 和 Ubuntu 都是基于 Debian内核 的 Linux 发行版ÿ…...
[ICLR 2022]How Much Can CLIP Benefit Vision-and-Language Tasks?
论文网址:pdf 英文是纯手打的!论文原文的summarizing and paraphrasing。可能会出现难以避免的拼写错误和语法错误,若有发现欢迎评论指正!文章偏向于笔记,谨慎食用 目录 1. 心得 2. 论文逐段精读 2.1. Abstract 2…...
【JavaWeb】Docker项目部署
引言 之前学习了Linux操作系统的常见命令,在Linux上安装软件,以及如何在Linux上部署一个单体项目,大多数同学都会有相同的感受,那就是麻烦。 核心体现在三点: 命令太多了,记不住 软件安装包名字复杂&…...
Hive 存储格式深度解析:从 TextFile 到 ORC,如何选对数据存储方案?
在大数据处理领域,Hive 作为 Hadoop 生态中重要的数据仓库工具,其存储格式的选择直接影响数据存储成本、查询效率和计算资源消耗。面对 TextFile、SequenceFile、Parquet、RCFile、ORC 等多种存储格式,很多开发者常常陷入选择困境。本文将从底…...
【7色560页】职场可视化逻辑图高级数据分析PPT模版
7种色调职场工作汇报PPT,橙蓝、黑红、红蓝、蓝橙灰、浅蓝、浅绿、深蓝七种色调模版 【7色560页】职场可视化逻辑图高级数据分析PPT模版:职场可视化逻辑图分析PPT模版https://pan.quark.cn/s/78aeabbd92d1...
iOS性能调优实战:借助克魔(KeyMob)与常用工具深度洞察App瓶颈
在日常iOS开发过程中,性能问题往往是最令人头疼的一类Bug。尤其是在App上线前的压测阶段或是处理用户反馈的高发期,开发者往往需要面对卡顿、崩溃、能耗异常、日志混乱等一系列问题。这些问题表面上看似偶发,但背后往往隐藏着系统资源调度不当…...
CVE-2020-17519源码分析与漏洞复现(Flink 任意文件读取)
漏洞概览 漏洞名称:Apache Flink REST API 任意文件读取漏洞CVE编号:CVE-2020-17519CVSS评分:7.5影响版本:Apache Flink 1.11.0、1.11.1、1.11.2修复版本:≥ 1.11.3 或 ≥ 1.12.0漏洞类型:路径遍历&#x…...
音视频——I2S 协议详解
I2S 协议详解 I2S (Inter-IC Sound) 协议是一种串行总线协议,专门用于在数字音频设备之间传输数字音频数据。它由飞利浦(Philips)公司开发,以其简单、高效和广泛的兼容性而闻名。 1. 信号线 I2S 协议通常使用三根或四根信号线&a…...
【电力电子】基于STM32F103C8T6单片机双极性SPWM逆变(硬件篇)
本项目是基于 STM32F103C8T6 微控制器的 SPWM(正弦脉宽调制)电源模块,能够生成可调频率和幅值的正弦波交流电源输出。该项目适用于逆变器、UPS电源、变频器等应用场景。 供电电源 输入电压采集 上图为本设计的电源电路,图中 D1 为二极管, 其目的是防止正负极电源反接, …...
MySQL:分区的基本使用
目录 一、什么是分区二、有什么作用三、分类四、创建分区五、删除分区 一、什么是分区 MySQL 分区(Partitioning)是一种将单张表的数据逻辑上拆分成多个物理部分的技术。这些物理部分(分区)可以独立存储、管理和优化,…...
