代理模式详解(重点解析JDK动态代理)
- 定义
在解析动态代理模式之前,先简单看下整个代理模式。代理模式分为普通代理、强制模式、动态代理模式。其中动态代理模式主要实现方式为Java JDK提供的JDK动态代理,第三方类库提供的,例如CGLIB动态代理。
代理模式就是为其他对象提供一种代理以控制对这个对象的访问。
- 通用类图

- 代理模式的优点
* 职责清晰
真实的角色就是实现实际的业务逻辑,不用关心其他非职责的事务,通过后期的代理完成一件事务,附带的结果就是编程简洁清晰。
* 高扩展性
具体主题角色是随时都会发生变化的,只要它实现了接口,甭管它如何变化,都逃不脱如来佛的手掌(接口),那我们的代理类完全就可以在不做任何修改的情况下使用。
* 智能化
一个类可以实现多个接口,完成不同任务的整合。也就是说代理类不仅可以实现主题接口,也可以实现其他接口完成不同的任务,而且代理的目的是在目标对象方法的基础上作增强,这种增强的本质通常就是对目标对象的方法进行拦截和过滤。
- 普通代理
* 定义
定义:普通代理就是我们要知道代理的存在,也就是类似的GamePlayerProxy这个类的存在,然后才能访问;在该模式下,调用者只知代理而不用知道真实的角色是谁,屏蔽了 真实角色的变更对高层模块的影响,真实的主题角色想怎么修改就怎么修改,对高层次的模 块没有任何的影响,只要你实现了接口所对应的方法,该模式非常适合对扩展性要求较高的 场合。当然,在实际的项目中,一般都是通过约定来禁止new一个真实的角色,这也是一个 非常好的方案。
* 类图

* 普通代理包含的角色
- 真实类(被代理类):实际完成业务逻辑的类
- 代理类
* 下面来看看具体的演示代码
#IGamePlayer接口:
public interface IGamePlayer {void login();void killBoss();void upgrade();
}
# GamePlayer类
package com.zoujieli.design.mode.proxy.general;public class GamePlayer implements IGamePlayer{private String name = null;public GamePlayer(IGamePlayer gamePlayer, String name) {if (gamePlayer == null) {throw new RuntimeException("不能创建真实对象");}this.name = name;}@Overridepublic void login() {System.out.println(name + "登陆游戏了");}@Overridepublic void killBoss() {System.out.println(name + "开始打BOSS了");}@Overridepublic void upgrade() {System.out.println(name + "升级了");}
}
#代理类
package com.zoujieli.design.mode.proxy.general;//普通代理模式
public class GamePlayerProxy implements IGamePlayer{private GamePlayer gamePlayer;public GamePlayerProxy(String name) {this.gamePlayer = new GamePlayer(this, name);}@Overridepublic void login() {this.gamePlayer.login();}@Overridepublic void killBoss() {this.gamePlayer.killBoss();}@Overridepublic void upgrade() {this.gamePlayer.upgrade();}
}
# 场景类 clientpublic class Client {public static void main(String[] args) {GamePlayerProxy proxy = new GamePlayerProxy("张三");proxy.login();proxy.killBoss();proxy.upgrade();}
}
普通代理是比较简单的一种代理模式
- 强制代理
* 定义:
强制代理则 是调用者直接调用真实角色,而不用关心代理是否存在,其代理的产生是由真实角色决定。
* 类图1:代理类实现了单个接口

* 类图2:代理类实现了多个接口

下面看看具体演示代码
#业务接口类public interface IGamePlayer {void login();void killBoss();void upgrade();IGamePlayer getProxy();
}
# 被代理类public class GamePlayer implements IGamePlayer {private String name = null;private IGamePlayer proxy = null;public GamePlayer(String name) {this.name = name;}@Overridepublic void login() {if (this.proxy == null) {throw new RuntimeException("请使用代理者");}System.out.println(name + "登陆游戏了");}@Overridepublic void killBoss() {if (this.proxy == null) {throw new RuntimeException("请使用代理者");}System.out.println(name + "开始打BOSS了");}@Overridepublic void upgrade() {if (this.proxy == null) {throw new RuntimeException("请使用代理者");}System.out.println(name + "升级了");}@Overridepublic IGamePlayer getProxy() {this.proxy = new GamePlayerProxy(this);return this.proxy;}
}
#代理类//普通代理模式
public class GamePlayerProxy implements IGamePlayer, IProxy{private GamePlayer gamePlayer;public GamePlayerProxy(GamePlayer gamePlayer) {this.gamePlayer = gamePlayer;}@Overridepublic void login() {this.gamePlayer.login();}@Overridepublic void killBoss() {this.gamePlayer.killBoss();}@Overridepublic void upgrade() {this.gamePlayer.upgrade();this.count();}@Overridepublic IGamePlayer getProxy() {return this;}@Overridepublic void count() {System.out.println("代练费100");}
}
# 代理接口类public interface IProxy {void count();
}
- 动态代理
* 定义
动态代理是在实现阶段不用关心代理谁,而在运行阶段 才指定代理哪一个对象。相对来说,自己写代理类的方式就是静态代理。
* 类图
类图说明:其中invoke方法是接口InvocationHandler定义必须实现的,它完成对真实方法的调用。我 们来详细讲解一下InvocationHandler接口,动态代理是根据被代理的接口生成所有的方法, 也就是说给定一个接口,动态代理会宣称“我已经实现该接口下的所有方法了”,那各位读者 想想看,动态代理怎么才能实现被代理接口中的方法呢?默认情况下所有的方法返回值都是 空的,是的,代理已经实现它了,但是没有任何的逻辑义,那怎么办?好办,通过 InvocationHandler接口,所有方法都由该Handler来进行处理,即所有被代理的方法都由 InvocationHandler接管实际的处理任务。
下面是JDK提供的InvocationHandler
public interface InvocationHandler {public Object invoke(Object proxy, Method method, Object[] args)throws Throwable;
}
* 类图2

这个类图中增加了Iadvice接口,作用是在调用业务方法的时候加入通知。这是两条独立发展的线路。动态代理实现代理的职责,业务逻辑Subject实现相关的 逻辑功能,两者之间没有必然的相互耦合的关系。通知Advice从另一个切面切入,最终在高层模块也就是Client进行耦合,完成逻辑的封装任务。
* 类图2的调用过程如下:

类图2的代码演示:
public class GamePlayer implements IGamePlayer {private String name = null;public GamePlayer(String name) {this.name = name;}@Overridepublic void login() {System.out.println(name + "登陆游戏了");}@Overridepublic void killBoss() {System.out.println(name + "开始打BOSS了");}@Overridepublic void upgrade() {System.out.println(name + "升级了");}
}
public interface IGamePlayer {void login();void killBoss();void upgrade();
}
public class GamePlayerInvocationHandler implements InvocationHandler {Object obj = null;public GamePlayerInvocationHandler(Object o) {this.obj = o;}@Overridepublic Object invoke(Object proxy, Method method, Object[] args) throws Throwable {Object invoke = method.invoke(this.obj, args);if (method.getName().equals("login")) {System.out.println("有人在用我的账号登录!");}return invoke;}
}
import java.lang.reflect.Proxy;public class DynamicProxy {public static <T> T newProxyInstance(IGamePlayer gamePlayer) {if (true) {new BeforeAdvice().beforeAdvice();}T proxy = (T) Proxy.newProxyInstance(gamePlayer.getClass().getClassLoader(),gamePlayer.getClass().getInterfaces(),new GamePlayerInvocationHandler(gamePlayer));return proxy;}
}
public interface IAdvice {void beforeAdvice();
}
public class BeforeAdvice implements IAdvice{@Overridepublic void beforeAdvice() {System.out.println("前置通知调用了");}
}
public class Client {public static void main(String[] args) {GamePlayer player = new GamePlayer("张三");IGamePlayer proxy = DynamicProxy.newProxyInstance(player);proxy.login();proxy.killBoss();proxy.upgrade();}
}
调试时,只要看到类似$Proxy0这样的结构,你就应该知道这是一 个动态代理了。
相关文章:
代理模式详解(重点解析JDK动态代理)
- 定义 在解析动态代理模式之前,先简单看下整个代理模式。代理模式分为普通代理、强制模式、动态代理模式。其中动态代理模式主要实现方式为Java JDK提供的JDK动态代理,第三方类库提供的,例如CGLIB动态代理。 代理模式就是为其他对象提供一种…...
【大厂AI课学习笔记】1.3 人工智能产业发展(2)
(注:腾讯AI课学习笔记。) 1.3.1 需求侧 转型需求:人口红利转化为创新红利。 场景丰富:超大规模且多样的应用场景。主要是我们的场景大,数据资源丰富。 抗疫加速:疫情常态化,催生新…...
【Python】一个简单的小案例:实现将两张图片合并为一张
使用时保证已经安装了opencv-python import cv2bg "BG.jpg" # 背景图名称 fg "FG.jpg" # 前景图名称 output_filename "new.jpg" # 合成后图片名称img_bg cv2.imread(bg) # 读取背景图 img_fg cv2.imread(fg) # 读取前景图# 读取背景…...
不同的强化学习模型适配与金融二级市场的功能性建议
DQN ES DDPG A2C TD3 SAC QMIX MADDPG PPO CQL IMPALA 哪个模型适合进行股票操作 在考虑使用哪种模型进行股票操作时,需要考虑模型的特点、适用场景以及实现复杂度等因素。以下是对您列出的几种强化学习模型的简要概述,以帮助您做出选择: DQ…...
【音视频原理】音频编解码原理 ③ ( 音频 比特率 / 码率 | 音频 帧 / 帧长 | 音频 帧 采样排列方式 - 交错模式 和 非交错模式 )
文章目录 一、音频 比特率 / 码率1、音频 比特率2、音频 比特率 案例3、音频 码率4、音频 码率相关因素5、常见的 音频 码率6、视频码率 - 仅做参考 二、音频 帧 / 帧长1、音频帧2、音频 帧长度 三、音频 帧 采样排列方式 - 交错模式 和 非交错模式1、交错模式2、非交错模式 一…...
spring常用语法
etl表达式解析 if (rawValue ! null && rawValue.startsWith("#{") && entryValue.endsWith("}")) { // assume its spel StandardEvaluationContext context new StandardEvaluationContext(); context.setBeanResolver(new Be…...
【计算机毕业设计】128电脑配件销售系统
🙊作者简介:拥有多年开发工作经验,分享技术代码帮助学生学习,独立完成自己的项目或者毕业设计。 代码可以私聊博主获取。🌹赠送计算机毕业设计600个选题excel文件,帮助大学选题。赠送开题报告模板ÿ…...
换个思维方式快速上手UML和 plantUML——类图
和大多数朋友一样,Jeffrey 在一开始的时候也十分的厌烦软件工程的一系列东西,对工程化工具十分厌恶,觉得它繁琐,需要记忆很多没有意思的东西。 但是之所以,肯定有是因为。对工程化工具的不理解和不认可主要是基于两个逻…...
策略模式+SpringBoot接口,一个接口实现接收的数据自动分流处理
策略模式 定义了算法族,分别封装起来,让它们之间可以互相替换,此模式让算法的变化,不会影响到使用算法的客户。策略模式的精髓就在于将经常变化的一点提取出来,单独变成一类,并且各个类别可以相互替换和组合。 1、策略接口 CalculationStrategy //算数 public interface…...
P1228 地毯填补问题(葬送的芙蓉王【bushi】)
地毯填补问题 题目描述 相传在一个古老的阿拉伯国家里,有一座宫殿。宫殿里有个四四方方的格子迷宫,国王选择驸马的方法非常特殊,也非常简单:公主就站在其中一个方格子上,只要谁能用地毯将除公主站立的地方外的所有地…...
352. 闇の連鎖(树上差分,LCA)
352. 闇の連鎖 - AcWing题库 传说中的暗之连锁被人们称为 Dark。 Dark 是人类内心的黑暗的产物,古今中外的勇者们都试图打倒它。 经过研究,你发现 Dark 呈现无向图的结构,图中有 N 个节点和两类边,一类边被称为主要边ÿ…...
dcat admin + dingo + nginx 开发前台
前言 Dcat Admin 是一个功能强大的后端框架,主要用于开发管理后台。然而,大多数网站不仅需要一个管理后台,还需要一个用户界面,即“前台”,以及它们自己的用户系统。 为了实现这一目标,我们需要对 Dcat A…...
安卓线性布局LinearLayout
<?xml version"1.0" encoding"utf-8"?> <LinearLayout xmlns:android"http://schemas.android.com/apk/res/android"xmlns:tools"http://schemas.android.com/tools"android:layout_width"match_parent"android:…...
Advanced CNN
文章目录 回顾Google NetInception1*1卷积Inception模块的实现网络构建完整代码 ResNet残差模块 Resedual Block残差网络的简单应用残差实现的代码 练习 回顾 这是一个简单的线性的卷积神经网络 然而有很多更为复杂的卷积神经网络。 Google Net Google Net 也叫Inception V…...
判断当前设备是不是安卓或者IOS?
代码(重要点): 当前文件要是 xxx.js文件,就需要写好代码后调用才会执行: // 判断是不是安卓 const isAndroid () > {return /android/.test(navigator.userAgent.toLowerCase()); }// 判断是不是ios const isIOS () > {return /iphone|ipad|ipod/.test(navigator.use…...
使用C++操作Matlab中的mat文件
matlab提供读写MAT文件的头文件和库函数,下面列出这些文件的路径,其中matlabroot指matlab安装的路径,arch来识别平台架构 头文件在matlabroot\extern\include库函数在matlabroot\bin\win64例程在matlabroot\extern\examples\eng_mat头文件 …...
【OCPP】ocpp1.6协议第3.5章节:本地授权和离线行为-介绍及翻译
目录 3.5章节 概述 3.5 本地鉴权和离线行为-译文(Local Authorization & Offline Behavior) 3.5.1 鉴权缓存-译文(3.5.1. Authorization Cache) 3.5.2 本地鉴权列表-译文(Local Authorization List) 3.5.3 授权缓存和本地授权列表之间的关系-译文(Relation between A…...
OpenGL查询对象 Query Objects
查询对象和异步查询(Query Objects and Asynchronous Queries) Query Objects(查询对象)是OpenGL中的一种机制,用于获取有关一系列GL命令处理过程的信息。这些信息可以包括: 绘图命令处理的图元数量。写入变换反馈缓冲区的图元数…...
【数据分享】1929-2023年全球站点的逐日最高气温数据(Shp\Excel\免费获取)
气象数据是在各项研究中都经常使用的数据,气象指标包括气温、风速、降水、湿度等指标,其中又以气温指标最为常用!说到气温数据,最详细的气温数据是具体到气象监测站点的气温数据! 之前我们分享过1929-2023年全球气象站…...
Docker深入解析:从基础到实践
Docker基础知识 Docker是什么:定义和核心概念解释 Docker是一个开源项目,它诞生于2013年,旨在自动化应用程序的部署过程, 让应用程序能够在轻量级的、可移植的、自给自足的容器中运行。这些容器可以在几乎任何机器上运行…...
别再为Tesseract中文识别报错发愁了!手把手教你搞定chi_sim语言包和环境变量配置
Tesseract中文识别实战:从报错排查到精准配置的全流程指南 当你在终端兴奋地输入第一行Tesseract命令,却看到刺眼的Failed loading language chi_sim报错时,那种挫败感我深有体会。这个看似简单的错误背后,往往隐藏着路径配置、文…...
量子-经典混合计算平台架构:从监控溯源到弹性推理引擎
1. 项目概述:当量子计算遇见经典算力最近几年,我身边不少做高性能计算和AI的朋友,都开始把目光投向一个听起来有点“科幻”的领域——量子计算。但大家聊着聊着,总会回到一个非常现实的问题:我们实验室那台价值不菲的量…...
从一根线到稳定画面:深入解读HDMI TMDS差分信号的PCB设计要点(阻抗控制与端接电容)
从一根线到稳定画面:深入解读HDMI TMDS差分信号的PCB设计要点(阻抗控制与端接电容) 在4K/8K超高清视频逐渐普及的今天,HDMI接口作为消费电子领域最主流的数字视频传输标准,其信号完整性设计直接决定了最终画质表现。许…...
魔兽争霸3终极兼容方案:5分钟解决Win10/Win11运行问题
魔兽争霸3终极兼容方案:5分钟解决Win10/Win11运行问题 【免费下载链接】WarcraftHelper Warcraft III Helper , support 1.20e, 1.24e, 1.26a, 1.27a, 1.27b 项目地址: https://gitcode.com/gh_mirrors/wa/WarcraftHelper 还在为魔兽争霸3在现代Windows系统上…...
蛋白质基础模型:从AlphaFold2到Chai-1的范式跃迁
1. 项目概述:一场悄然发生的蛋白质结构预测范式迁移最近在实验室跑完第7轮Chai-1的微调任务后,我盯着屏幕上跳出来的pLDDT值曲线,突然意识到:我们正在经历的不是一次工具升级,而是一场底层建模逻辑的彻底重写。标题里提…...
GPT-4的1.8T参数与2%激活率:MoE架构原理与工程真相
1. 项目概述:参数规模与稀疏激活的真相拆解“GPT-4 Has 1.8 Trillion Parameters. It Uses 2% of Them Per Token.”——这句话过去两年在技术社区反复刷屏,常被当作“大模型已突破算力瓶颈”的佐证,也常被误读为“GPT-4只用360亿参数&#x…...
C#与Unity 3D构建100ms级工业数字孪生系统
1. 这不是“3D大屏”,而是产线工控级实时映射“数字孪生监控”这六个字,现在被贴在太多PPT封面上了——三维建模、粒子特效、旋转飞入的UI动效,配上“智能决策”“预测性维护”的标语,看起来很美。但真正跑在车间里的产线监控系统…...
hccl:昇腾 NPU 的“多卡通信库”
hccl:昇腾 NPU 的“多卡通信库” 之前帮朋友看多 NPU 训练的代码,发现他自己手写了很多通信算子(AllReduce/Broadcast/AllGather 等)——在多 NPU 之间传数据,光写通信层就写了 3,000 行,而且还不稳定&…...
12个简单步骤:CFDPython教你从零掌握计算流体动力学核心算法
12个简单步骤:CFDPython教你从零掌握计算流体动力学核心算法 【免费下载链接】CFDPython A sequence of Jupyter notebooks featuring the "12 Steps to Navier-Stokes" http://lorenabarba.com/ 项目地址: https://gitcode.com/gh_mirrors/cf/CFDPyth…...
实测taotoken在不同时段api调用的响应延迟与稳定性表现
🚀 告别海外账号与网络限制!稳定直连全球优质大模型,限时半价接入中。 👉 点击领取海量免费额度 实测taotoken在不同时段api调用的响应延迟与稳定性表现 对于依赖大模型API进行开发的团队而言,服务的响应延迟与稳定性…...
