代理模式:控制对象访问的中间层设计
代理模式:控制对象访问的中间层设计
一、模式核心:通过代理对象控制对目标对象的访问
在软件开发中,有时需要为对象添加一个 “代理” 来控制对它的访问,例如:
- 远程代理:访问远程对象时(如 RPC 调用),本地代理对象伪装成远程对象
- 虚拟代理:延迟加载目标对象(如图片未加载时显示占位符)
- 保护代理:控制对敏感对象的访问权限(如用户权限校验)
** 代理模式(Proxy Pattern)** 通过引入代理类,在不修改目标对象的前提下,为其添加额外的逻辑或控制访问,核心解决:
- 访问控制:在目标对象访问前后添加预处理逻辑
- 资源优化:延迟初始化昂贵的目标对象
- 职责分离:将非业务逻辑(如日志、事务)从目标对象中剥离
核心思想与 UML 类图(PlantUML 语法)
代理模式包含目标接口(Subject)、目标对象(RealSubject)和代理对象(Proxy),代理对象与目标对象实现相同接口,客户端通过代理间接访问目标:
二、核心实现:虚拟代理实现图片延迟加载
1. 定义目标接口(图片)
public interface Image {void display(); // 显示图片
}
2. 实现真实主题(实际图片对象,加载耗时)
public class RealImage implements Image {private String fileName;public RealImage(String fileName) {this.fileName = fileName;loadFromDisk(fileName); // 模拟加载耗时操作}private void loadFromDisk(String fileName) {System.out.println("加载图片:" + fileName);try {Thread.sleep(1000); // 模拟IO延迟} catch (InterruptedException e) {e.printStackTrace();}}@Overridepublic void display() {System.out.println("显示图片:" + fileName);}
}
3. 实现代理对象(延迟加载,先显示占位符)
public class ImageProxy implements Image {private String fileName;private RealImage realImage; // 真实对象延迟初始化public ImageProxy(String fileName) {this.fileName = fileName;}@Overridepublic void display() {if (realImage == null) {System.out.println("显示占位符..."); // 前置处理realImage = new RealImage(fileName); // 首次调用时加载真实对象}realImage.display(); // 调用真实对象的显示方法System.out.println("记录访问日志:" + fileName); // 后置处理}
}
4. 客户端通过代理访问目标对象
public class ClientDemo {public static void main(String[] args) {// 使用代理对象,无需直接创建RealImageImage image = new ImageProxy("large_image.jpg");System.out.println("第一次显示图片:");image.display(); // 触发延迟加载System.out.println("\n第二次显示图片:");image.display(); // 直接使用缓存的RealImage}
}
输出结果:
第一次显示图片:
显示占位符...
加载图片:large_image.jpg
显示图片:large_image.jpg
记录访问日志:large_image.jpg第二次显示图片:
显示图片:large_image.jpg
记录访问日志:large_image.jpg
三、进阶:实现分布式代理与动态代理
1. 远程代理(模拟 RPC 调用)
// 远程服务接口(目标接口)
public interface RemoteService {String process(String request);
}// 本地代理对象(伪装成远程服务)
public class RemoteServiceProxy implements RemoteService {private String serverUrl;public RemoteServiceProxy(String serverUrl) {this.serverUrl = serverUrl;}@Overridepublic String process(String request) {// 通过HTTP/Netty发送请求到远程服务器return sendRequestToServer(request);}private String sendRequestToServer(String request) {System.out.println("发送远程请求:" + request + " 到 " + serverUrl);// 实际实现需处理网络IO和序列化return "远程响应:" + request.toUpperCase();}
}
2. 动态代理(基于 Java 反射,无需手动编写代理类)
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;// 动态代理处理器
public class DynamicProxyHandler implements InvocationHandler {private Object target; // 目标对象public DynamicProxyHandler(Object target) {this.target = target;}@Overridepublic Object invoke(Object proxy, Method method, Object[] args) throws Throwable {System.out.println("动态代理前置处理:" + method.getName());Object result = method.invoke(target, args); // 调用目标对象方法System.out.println("动态代理后置处理:" + method.getName());return result;}
}// 创建动态代理示例
public class DynamicProxyDemo {public static void main(String[] args) {RealImage realImage = new RealImage("small_image.jpg");// 生成动态代理对象Image proxy = (Image) Proxy.newProxyInstance(Image.class.getClassLoader(),new Class<?>[] { Image.class },new DynamicProxyHandler(realImage));proxy.display(); // 通过代理调用目标方法}
}
3. 可视化代理流程
四、框架与源码中的代理模式实践
1. Spring AOP(动态代理实现切面编程)
- 通过
JdkDynamicAopProxy
或CglibAopProxy
生成代理对象,织入切面逻辑
// 代理对象调用目标方法时,自动执行@Before、@After等增强
@Service
public class UserService {@Transactionalpublic void updateUser(User user) {// 业务逻辑}
}
2. MyBatis 映射器(Mapper Proxy)
MapperProxy
作为代理对象,将接口方法映射为 SQL 语句执行
public interface UserMapper {@Select("SELECT * FROM users WHERE id = #{id}")User getUser(int id);
}// MyBatis创建MapperProxy代理对象
UserMapper mapper = sqlSession.getMapper(UserMapper.class);
User user = mapper.getUser(1); // 代理对象处理SQL执行
3. JavaScript 代理(Proxy 对象)
- ES6 提供
Proxy
用于创建代理对象,拦截目标对象的操作
const realObject = { name: "Alice" };
const proxy = new Proxy(realObject, {get(target, property) {console.log(`访问属性:${property}`);return target[property];}
});
console.log(proxy.name); // 输出:访问属性:name Alice
五、避坑指南:正确使用代理模式的 3 个要点
1. 区分代理与装饰器模式
- 代理模式:代理对象控制对目标对象的访问(目标对象可能不存在或需控制访问)
- 装饰器模式:装饰对象增强目标对象的功能(目标对象必须存在且功能需扩展)
2. 处理代理对象的线程安全
- 若代理对象持有目标对象的引用,需确保多线程环境下的线程安全
public class ThreadSafeProxy implements Subject {private RealSubject realSubject = new RealSubject();private final Object lock = new Object();@Overridepublic void request() {synchronized (lock) {realSubject.request();}}
}
3. 避免代理链过长
- 多层代理可能导致性能损耗和调试困难,建议:
- 合并同类代理(如日志代理与权限代理合并为一个复合代理)
- 使用 AOP 替代多层手动代理
4. 反模式:滥用代理导致复杂度上升
- 对于简单的功能增强,直接修改目标对象可能更高效,无需引入代理
六、总结:何时该用代理模式?
适用场景 | 核心特征 | 典型案例 |
---|---|---|
远程对象访问 | 目标对象位于远程服务器,需通过网络调用 | RPC 框架、微服务客户端 |
延迟加载与缓存 | 目标对象创建昂贵,需延迟初始化 | 图片 / 视频加载、大文件处理 |
权限控制与日志记录 | 需要在目标对象访问前后添加通用逻辑 | 权限系统、事务管理、性能监控 |
接口伪装与隔离 | 需要为复杂系统提供简单接口或伪装实现细节 | 模拟对象(测试场景)、遗留系统适配 |
代理模式通过 “中间层控制 + 解耦访问” 的设计,为对象访问添加了灵活的控制层,是构建可扩展、易维护系统的重要模式。下一篇我们将深入探讨策略模式,解析如何动态切换算法实现,敬请期待!
扩展思考:静态代理 vs 动态代理
类型 | 实现方式 | 灵活性 | 适用场景 |
---|---|---|---|
静态代理 | 手动编写代理类(编译期确定) | 低(代理类与目标类强绑定) | 简单场景、无需频繁修改代理逻辑 |
动态代理 | 通过反射或字节码生成(运行时创建) | 高(可动态适配多个目标类) | 框架级代理(如 AOP、ORM) |
理解这种差异,能帮助我们在不同场景下选择更合适的代理实现方式。
相关文章:
代理模式:控制对象访问的中间层设计
代理模式:控制对象访问的中间层设计 一、模式核心:通过代理对象控制对目标对象的访问 在软件开发中,有时需要为对象添加一个 “代理” 来控制对它的访问,例如: 远程代理:访问远程对象时(如 R…...
Python类和对象二(十一)
构造函数: 重写: 通过类名访问类里面的方法的做法,称为调用未绑定的父类方法,他有时候会产生钻石继承问题: 发现A重复初始化了两次,类c同事继承类B1和B2,类B1和B2又是继承类A的,当c…...
大模型在代码安全检测中的应用
大模型在代码安全检测领域的应用近年来取得显著进展,尤其在代码审查(Code Review, CR)场景中展现出高效性与准确性。以下是其核心优势、技术路径、挑战及实践案例的总结: 一、技术优势与核心能力 语义理解与上下文分析 大模型通过…...
Python实现图片浏览器
Python实现图片浏览器 支持浏览多种常见图片格式:JPG, JPEG, PNG, GIF, BMP, TIFF, WEBP 通过"打开文件夹"按钮选择任何包含图片的文件夹 灵活的排序选项: 按时间排序(新→旧或旧→新) 按文件名排序(A→…...
网页设计规范:从布局到交互的全方位指南
网页设计规范看似繁杂,但其实都是为了给用户提供更好的体验。只有遵循这些规范,才能设计出既美观又实用的网页,让用户在浏览网页时感到舒适、愉悦。 一、用户体验至上 用户体验(UX)是网页设计的核心原则之一。设计师…...
哪些心电图表现无缘事业编体检呢?
根据《公务员录用体检通用标准》心血管系统条款及事业单位体检实施细则,心电图不合格主要涉及以下类型及处置方案: 一、心律失常类 早搏:包括房性早搏、室性早搏和交界性早搏。如果每分钟早搏次数较多(如超过5次)&…...
Java基础系列-HashMap源码解析1-BST树
文章目录 序二叉搜索树(BST)引入查找5插入9极端情况删除删除叶节点 10删除节点只有左子树或只有右子树删除节点既有左子树又有右子树为什么这么代替? 序 提到HashMap,就不得不提红黑树(HashMap1.8之后)&am…...
生物计算安全攻防战:从DNA存储破译到碳基芯片防御体系重构
随着碳基生物芯片突破冯诺依曼架构限制,DNA数据存储密度达到1EB/克量级,合成生物学与信息技术的融合正引发新一轮安全革命。本文深入解析碳基芯片逆向工程路径,揭示酶驱动DNA数据解码的技术突破,预警合成生物回路潜在的数据泄露风…...
【金仓数据库征文】从Oracle到KingbaseES的语法兼容与迁移
随着“信创”战略的深入推进,国产数据库逐渐成为IT系统的重要组成部分。KingbaseES(金仓数据库)凭借其良好的Oracle兼容性和日益完善的生态,成为金融、政务等核心行业国产化替代的重要选项。本文将从语法兼容性分析出发࿰…...
MATLAB 下载安装教程
## 一、下载MATLAB 1. 访问 MathWorks 官方网站:https://www.mathworks.com/ 2. 点击右上角的"登录"按钮 - 如果没有账号,需要先注册一个 MathWorks 账号 - 学生可以使用教育邮箱注册,获得教育版授权 3. 登录后,点击&…...
Android kotlin通知功能完整实现指南:从基础到高级功能
本文将详细介绍如何在Android应用中实现通知功能,包括基础通知、动作按钮和内联回复等高级特性。 一、基础通知实现 1. 基本通知发送方法 fun sendBasicNotification(context: Context, title: String, message: String) {// 1. 创建通知渠道(Android 8.0必需)va…...
Javase 基础入门 —— 04 继承
本系列为笔者学习Javase的课堂笔记,视频资源为B站黑马程序员出品的《黑马程序员JavaAI智能辅助编程全套视频教程,java零基础入门到大牛一套通关》,章节分布参考视频教程,为同样学习Javase系列课程的同学们提供参考。 01 什么是继…...
2.4/Q2,Charls最新文章解读
文章题目:The impact of hearing ability on depression among retired middle-aged and elderly individuals in China: the chain mediating role of self-rated health and life satisfaction DOI:10.1186/s41043-025-00791-9 中文标题:中…...
对流对象的理解
在c里,“流”可以理解为数据传输与操作的“介质”。 从输入输出角度来看,有输入流(比如cin)和输出流(cout)。对于输入流,数据通过它从外部设备(例如键盘)“流入”程序内…...
RBAC权限-笔记
1. RBAC模型简介 1.1. RBAC三要素 RBAC权限模型(Role-Based Access Control:基于角色的访问控制)有3个基础组成部分,分别是:用户、角色和权限。它们之间的关系如下图所示: 用户(User)…...
stm32之GPIO函数详解和上机实验
目录 1.LED和蜂鸣器1.1 LED1.2 蜂鸣器 2.实验2.1 库函数:RCC和GPIO2.1.1 RCC函数1. RCC_AHBPeriphClockCmd2. RCC_APB2PeriphClockCmd3. RCC_APB1PeriphClockCmd 2.1.2 GPIO函数1. GPIO_DeInit2. GPIO_AFIODeInit3. GPIO_Init4. GPIO_StructInit5. GPIO_ReadInputDa…...
MsQuick编译和使用
MsQuick编译和使用 编译克隆代码使用cmakevs2022编译 使用示例 编译 克隆代码 git clone --recurse-submodules https://github.com/microsoft/msquic.git使用cmakevs2022编译 然后直接configure之后Generate然后打开vs工程编译即可生成动态库 使用示例 #include <s…...
01 ubuntu中wps桌面快捷键无法使用
文章目录 1. 问题描述:2. 解决方法:3. 结果展示4. 参考 1. 问题描述: 2. 解决方法: 添加权限 chmod 755 ./wps-office-prometheus.desktop 右键选择允许运行 3. 结果展示 修改前 修改后 4. 参考 参考1...
云原生后端架构:重塑后端开发的新范式
📝个人主页🌹:慌ZHANG-CSDN博客 🌹🌹期待您的关注 🌹🌹 一、引言:后端开发的新时代正在到来 传统的后端开发常常面临如下挑战:部署流程复杂、环境不一致、系统难以扩展、监控能力薄弱、上线流程缓慢。在企业数字化转型、业务快速迭代的大背景下,这些问题暴露得…...
Linux命令-tcpdump
tcpdump 是一个功能强大的网络数据包捕获和分析工具。以下是 tcpdump 命令的完整参数列表及说明: 参数 -a 将网络地址和广播地址转换为名字 tcpdump -a -i eth0-A 以 ASCII 格式打印所有分组,最小化链路层头部信息 tcpdump -A-b 在数据链路层上选择协议…...
分糖果——牛客
链接:登录—专业IT笔试面试备考平台_牛客网 来源:牛客网 题目描述 幼儿园准备了nnn包糖果,每包糖果里有111、222或333颗美味的糖果。现在需要将这些这些糖果平分给两个表现优异的小朋友以作奖励,为了公平公正,需要…...
L0、L2和L∞范数这三种范数的区别
目录 一、解释 1. L0范数:数一数你有多少件行李 2. L2范数:别把行李塞得太满 3. L∞范数:别带任何超重的东西 一句话总结 二、作用 1. L0范数的作用:做减法,只留最重要的…...
[实战]zynq7000设备树自动导出GPIO
目录 zynq7000设备树自动导出GPIO添加设备树节点验证实验 结论 zynq7000设备树自动导出GPIO 今天无聊,掏出我82年产的microzed玩一玩。玩啥好呢,要不点个灯吧。于是,三下五除二,通过linux sys接口以及echo,很快就点亮…...
java六人打分
import java.util.Scanner;public class HelloWorld {public static void main(String[] args) {//打分平均分System.out.println("请输入六个评分");Scanner sc new Scanner(System.in);double[] score new double[6];for(int i0;i<score.length;i){System.ou…...
量子计算浪潮下的安全应对之法
量子计算凭借其强大的计算能力,被传言能够在极短时间内秒级破解传统计算机需耗时漫长岁月(以万年算)才能解开的密码,成为了近年来人们讨论的热点。这看似高深的科技名词在网络安全中又扮演着何种角色?我们应从当前人们…...
Windows Server 2022 常见问题解答
一、安装与部署 1.1 系统要求 硬件配置:最低需要 1.4 GHz 64 位处理器、512 MB 内存、32 GB 硬盘空间。但在实际生产环境中,为确保系统流畅运行,建议使用 2.0 GHz 以上处理器、8 GB 以上内存和 100 GB 以上硬盘。软件兼容性:与大多数基于 Windows 的企业级应用兼容,但在安…...
项目组合管理PPM
项目组合管理(Project Portfolio Management, PPM)详述 一、定义与核心目标 定义 项目组合管理是通过系统化的方法,对组织的所有项目和项目集进行识别、选择、优先级排序、资源配置和动态监控,以确保其与战略目标一致,并最大化投资回报(ROI)的管理过程。 核心目标 战略…...
自建开源远程协助服务RustDesk —— 筑梦之路
开源项目 # 服务端https://github.com/rustdesk/rustdesk-server.git# 客户端https://github.com/rustdesk/rustdesk.git 搭建服务端 需要使用的端口、协议 hbbs - RustDesk ID 注册服务器 hbbr - RustDesk 中继服务器默认情况下,hbbs 监听 21115(tcp) , 21…...
【android bluetooth 协议分析 11】【AVDTP详解 2】【avdtp 初始化阶段主要回调关系梳理】
在车机中 a2dp 通常情况下作为 sink. 本篇来帮助各位 朋友梳理一下,这部分的初始化流程。 我们着重梳理 native 层的逻辑, framework - java 侧一般比较容易看明白, 暂时不做梳理。 如果需要笨叔梳理的可以在博客评论。 出专门的章节来梳理。…...
C++回顾 day3
宏定义的数据是在预处理发生了替换 const类型的数据是在编译阶段发生的替换 命名空间 namespace 空间名{int a;void func_print(){printf("func_print");}struct Stu{int x;char *y;};//或者其他命名空间 } Space::x 20; cout << Space::x;using Space::x;…...
机器学习算法-分类决策树
分类决策树算法-python实现 数据集 具体方法是:从根结点开始,对结点计算所有可能的特征的信息增益,选择信息增益最大的特征作为结点的特征,由该特征的不同取值建立子节点;再对子结点递归地调用以上方法,构…...
日语学习-日语知识点小记-构建基础-JLPT-N4阶段(9): 意向形
日语学习-日语知识点小记-构建基础-JLPT-N4阶段(9): 意向形 1、前言(1)情况说明(2)工程师的信仰 2、知识点(1)「~てしまう」=「~ちゃう…...
kotlin与MVVM结合使用总结(一)
一、Kotlin 与 MVVM 结合的核心优势 代码简洁性 数据类(data class)简化 Model 层定义,自动生成equals/hashCode/toString扩展函数简化 View 层逻辑(如点击事件扩展)lateinit/by lazy优化 ViewModel 属性初始化 异步处…...
达妙电机CAN通信及实验
项目进一步往下做的时候,要上实物了,需要用到达妙电机,虽然有说明书和例程,但是STM32控制电机的具体时间还是花了些时间,我的板子和例程的有些区别,中间很多地方都需要进行修改完善,而且还补充了…...
语音合成之四基于LLM的语音合成
基于LLM的语音合成 1.技术架构1.1 LlaSA1.2 CosyVoice (和 CosyVoice2)1.3 SparkTTS 2 特性对比2.1 零样本语音克隆2.2 多语种支持2.3 可控语音生成2.4 计算效率和模型大小 总结 当前,在大型语言模型(Large Language Models,LLMs)…...
Docker Python 官方镜像使用说明(TAG说明)
Docker Python 官方镜像使用说明(TAG说明) 本文将以python的3.12版本,详细讲解官方 Python 镜像 的TAGS含义 官方文档:https://github.com/tuonioooo/docker 🧭 一张图先看懂(最常见 Tag) py…...
Node.js 开发用户登录功能(使用mysql实现)
在 Web 开发中,用户登录功能是一个基础且重要的部分。、 一、环境搭建 在开始开发之前,我们需要搭建好相应的开发环境。以下是所需的工具和库: Node.js:作为 JavaScript 的运行环境,为我们的项目提供支持。mysql2&am…...
程序员学英文之Shipment Claim 运输和索赔
Time is precious , don’t waste your time, you should spend your time on something valuable . 时间很宝贵,不要浪费时间,你应该把时间用在有 价值的事情上。 Dia-1: Shipment by Voyage Charter 租船装运 1. May I know when your bo…...
python实战项目64:selenium采集软科中国大学排名数据
python实战项目64:selenium采集软科中国大学排名数据 一、项目需求二、流程分析三、完整代码一、项目需求 本项目的需求是使用selenium采集软科中国大学排名的数据。网站首页如下: 抓取此网页数据一般有两种方式,一种是直接发requests请求,我们这里采用的是使用selenium控…...
Linux服务器:在ufw防火墙设置这套规则sudo ufw allow from 172.0.0.0/8,为什么容器就可以访问宿主机的服务了?
在 Docker 环境中,容器默认使用 桥接网络(bridge),宿主机和容器之间的通信会受到防火墙(如 ufw)的限制。当你执行 sudo ufw allow from 172.0.0.0/8 后,容器可以访问宿主机上的服务,原因如下: 1. Docker 默认使用 172.x.x.x 网段 Docker 默认会创建一个 docker0 网桥…...
Google搜索技巧
谷歌搜索 1. 使用双引号 (" ") 精确匹配短语 ● 例子:"人工智能的定义" ● 作用:确保搜索结果中包含完全匹配的短语,而不是单独的单词。 2. 使用减号 (-) 排除特定词语 ● 例子:苹果 -水果 ● 作用&…...
Reactor编程模型介绍
Reactor 模型是一种基于事件驱动的编程模型,广泛应用于高并发网络服务器的设计中。它通过事件循环和回调机制,将事件的处理逻辑从主线程中解耦出来,从而实现高效的异步 I/O 操作。Reactor 模型的核心思想是利用一个或多个事件分发器(Reactor)来监听各种事件(如 I/O 事件、…...
C++笔记-stack_queue(含deque,priority_queue,仿函数的讲解)
一.stack和queue的基本使用 stack和queue就是我们之前所学的栈和队列,这两个和之前学的vector,list不太一样: 这是vector和list的,注意第一行中写的containers,代表这两个都是容器,但是: stac…...
意见反馈留言二维码制作
意见反馈对于工作整改具有重要作用,在工作中一味埋头苦干不如抬头多听听反馈声音。而传统的反馈内容投递后,因为繁琐性和时效性的枷锁,往往石沉大海,不知何时才能得到回应,这就导致反馈信息的延迟,一些时效…...
扣子智能体平台深度解读:功能剖析与全流程工作流详解
在上一篇文章中,我们已经带大家了解了“智能体”这一概念的内涵,并通过扣子智能体平台的各大模块做了初步介绍,同时用一个简单的示例演示了如何构建和部署第一个智能体。那篇文章打好了基础,让大家对智能体的基本组成与工作方式有…...
C语言五子棋项目
头文件与宏定义 #include <graphics.h> #include <conio.h> graphics.h:EasyX 图形库,提供图形绘制功能(画线、画圆、显示文字等)。 conio.h:提供控制台输入输出函数(这里只是为了兼容性&…...
建筑安全员 A 证与 C 证:差异决定职业方向
在建筑行业的职业发展道路上,安全员 A 证和 C 证就像两条不同的岔路,它们之间的差异,在很大程度上决定了从业者的职业方向。 从证书性质和用途来看,A 证是从业资格证书,更像是一把开启安全管理高层岗位的 “金钥匙”。…...
长连接、短连接与WebSocket的基本知识
目录 前言正文 前言 🤟 找工作,来万码优才:👉 #小程序://万码优才/r6rqmzDaXpYkJZF 爬虫神器,无代码爬取,就来:bright.cn Java基本知识: java框架 零基础从入门到精通的学习路线 附…...
MySQL常见问题解答
一、安装与配置问题 1. 安装失败(权限 / 依赖 / 端口冲突) 权限问题:以管理员身份运行安装程序(Windows)或使用sudo(Linux)。依赖缺失: Windows 需安装 Visual C++ Redistributable(如 2013 版)。Linux 通过包管理器安装依赖(如libaio、perl)。端口冲突: 检查 33…...
Codeforces Round 1019 (Div. 2)(ABCD)
A. Common Multiple 翻译: 给你一个整数数组 a1,a2,...,an。如果存在一个数组 y1,y2,...,ym,且 y 的元素是不同的(换句话说,对于所有 1≤i<j≤m 的数组,yi≠yj),并且对于所有 1≤i≤m 的数组…...