设计模式——代理设计模式(结构型)
摘要
本文详细介绍了代理设计模式,包括其定义、结构组成、实现方式、适用场景及实战示例。代理设计模式是一种结构型设计模式,通过代理对象控制对目标对象的访问,可增强功能或延迟加载等。文中通过类图、时序图、静态代理、JDK动态代理、CGLIB动态代理、Spring代理等方式阐述实现方式,并结合金融风控场景进行实战示例,最后对比分析了JDK动态代理和Spring-AOP实现方式。
1. 代理设计模式定义
代理设计模式(Proxy Pattern)是一种结构型设计模式,它为其他对象提供一种代理以控制对这个对象的访问。代理对象在客户端和目标对象之间起到中介作用,常用于控制对象访问、增强功能或延迟加载等场景。代理模式为某对象提供一个替身或占位符,以控制对这个对象的访问。
1.1.1. 📌 结构组成:
角色 | 说明 |
| 抽象主题,定义目标对象和代理的共同接口。 |
| 真实主题,实现实际业务逻辑。 |
| 代理对象,控制对真实主题的访问,可添加额外行为。 |
2. 代理设计模式结构
代理模式包含如下角色:
- Subject: 抽象主题角色
- Proxy: 代理主题角色
- RealSubject: 真实主题角色
2.1. 代理设计模式类图
2.2. 代理设计模式时序图
3. 代理设计模式实现方式
代理设计模式的实现方式有多种,主要分为 静态代理 和 动态代理(JDK 动态代理 & CGLIB 动态代理)。下面将依次介绍它们的实现方式及示例。
3.1. ✅ 静态代理(Static Proxy)
3.1.1. 🔧 实现步骤:
- 定义公共接口(抽象主题)
- 实现真实业务类(RealSubject)
- 编写代理类(Proxy),内部持有 RealSubject 对象,控制访问
3.1.2. 📦 示例:
// 抽象主题
public interface Service {void doWork();
}// 真实对象
public class RealService implements Service {public void doWork() {System.out.println("执行真实业务逻辑");}
}// 代理对象
public class ServiceProxy implements Service {private final RealService realService = new RealService();public void doWork() {System.out.println("前置日志记录");realService.doWork();System.out.println("后置监控统计");}
}
3.1.3. ✅ 使用:
Service service = new ServiceProxy();
service.doWork();
3.2. ✅ JDK 动态代理(基于接口)
3.2.1. 📌 要求:被代理的类必须实现接口。
3.2.2. 🔧 实现方式:
- 创建接口和实现类。
- 使用
InvocationHandler
实现增强逻辑。 - 通过
Proxy.newProxyInstance()
生成代理对象。
3.2.3. 📦 示例:
public interface Service {void doWork();
}public class RealService implements Service {public void doWork() {System.out.println("执行真实业务逻辑");}
}
public class LogInvocationHandler implements InvocationHandler {private final Object target;public LogInvocationHandler(Object target) {this.target = target;}public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {System.out.println("前置日志");Object result = method.invoke(target, args);System.out.println("后置日志");return result;}
}
Service proxy = (Service) Proxy.newProxyInstance(RealService.class.getClassLoader(),new Class[]{Service.class},new LogInvocationHandler(new RealService())
);
proxy.doWork();
3.3. ✅ CGLIB 动态代理(基于继承)
3.3.1. 📌 要求:目标类不能是 final
类,方法也不能是 final
。
3.3.2. 🔧 实现方式:
使用第三方库 CGLIB(如 Spring AOP 默认使用) 生成目标类的子类实现代理。
3.3.3. 📦 示例(使用 cglib
):
public class RealService {public void doWork() {System.out.println("执行真实业务逻辑");}
}
public class CglibMethodInterceptor implements MethodInterceptor {public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable {System.out.println("前置增强");Object result = proxy.invokeSuper(obj, args);System.out.println("后置增强");return result;}
}
Enhancer enhancer = new Enhancer();
enhancer.setSuperclass(RealService.class);
enhancer.setCallback(new CglibMethodInterceptor());
RealService proxy = (RealService) enhancer.create();
proxy.doWork();
3.4. ✅ Spring 中的代理(实际应用)
场景 | 使用方式 | 实现代理方式 |
AOP 切面增强 |
| JDK 或 CGLIB |
事务管理 |
| JDK 或 CGLIB |
缓存注解 |
| Spring AOP 代理 |
3.5. 📝 代理设计模式总结
实现方式 | 是否要求接口 | 是否可增强所有方法 | 是否支持 final 类 |
静态代理 | ✅ | ✅ | ✅ |
JDK 动态代理 | ✅ | ✅ | ❌ |
CGLIB 动态代理 | ❌ | ✅ | ❌ |
4. 代理设计模式适合场景
4.1. ✅ 适合使用代理模式的场景
场景 | 说明 |
权限控制 | 控制对敏感对象的访问,例如只有特定用户才能访问某些接口(安全代理)。 |
延迟加载 | 当对象创建成本高、初始化慢时,使用虚拟代理延迟加载资源(如图片、文件)。 |
远程代理(RPC) | 客户端调用代理对象,本质是远程服务器的接口封装,例如 Dubbo、gRPC 等远程服务调用代理。 |
记录日志/监控行为 | 在调用真实对象前后执行附加操作(如日志、性能监控等),例如 AOP 的典型应用。 |
事务控制/缓存控制 | 拦截业务逻辑前后控制事务边界或缓存处理,常见于 Spring 中 |
SpringAOP实现原理 | 基于代理对 Bean 进行横切增强。 |
防止重复提交或频繁调用 | 通过代理封装防抖节流逻辑。 |
4.2. ❌ 不适合使用代理模式的场景
场景 | 原因 |
业务逻辑简单,不需增强行为 | 引入代理会增加结构复杂度,得不偿失。 |
不需要拦截/控制访问 | 如果只是调用普通方法,不涉及权限、监控等,直接使用原始对象更清晰高效。 |
频繁变动或高并发敏感场景 | 动态代理在高频调用下可能存在性能问题,不如直接调用来得高效。 |
需要访问类中 方法或类(JDK 动态代理) | JDK 动态代理只能基于接口,不能代理 |
不具备接口或无法继承的目标类 | 无法被 JDK/CGLIB 等动态代理机制支持(如某些第三方封闭类)。 |
4.3. 📌 代理模式的场景总结:
项目 | 使用代理适合 | 不适合使用代理 |
是否需要权限/日志控制 | ✅ 是 | ❌ 否 |
是否希望延迟创建 | ✅ 是 | ❌ 否 |
对象构造是否昂贵 | ✅ 是 | ❌ 否 |
是否必须 final 类或方法 | ❌ 否(JDK/CGLIB 限制) | ✅ 是 |
是否对性能敏感 | ❌ 否(代理略有性能损耗) | ✅ 是 |
项目是否小而简单 | ❌ 否 | ✅ 是(复杂结构不划算) |
5. 代理设计模式实战示例
以下是一个在金融风控场景中,使用代理设计模式的 Spring Boot 实战示例。
5.1. 🧩 场景说明(金融风控)
系统中有一个核心接口:FraudChecker
(欺诈检查器)。不同风控规则实现了它,比如:
- 黑名单校验
- 设备风险评分
- IP 频次校验
你希望在调用真实校验逻辑前后增加:
- 日志记录
- 调用耗时监控
- 异常捕获/报警等
这就适合使用代理模式来封装增强行为。
5.2. ✅ 实现目标
- 使用 接口 + 真实实现类 + 代理类
- 所有 Bean 交给 Spring 容器管理
- 注入使用
@Autowired
,不使用构造函数注入 - 通过代理封装增强行为(记录日志 + 耗时统计)
5.3. 📁 项目结构如下:
com.example.riskcheck
├── FraudChecker.java // 抽象主题
├── RealFraudChecker.java // 真实对象
├── FraudCheckerProxy.java // 代理对象
├── FraudCheckerRunner.java // 启动测试类
5.4. 🔶 抽象接口 FraudChecker
public interface FraudChecker {void check(String userId);
}
5.5. 🔷 真实风控实现类 RealFraudChecker
@Component("realFraudChecker")
public class RealFraudChecker implements FraudChecker {@Overridepublic void check(String userId) {// 模拟业务逻辑System.out.println("执行真实的欺诈检查逻辑,用户ID: " + userId);// 可能抛出异常等}
}
5.6. 🔶 代理类 FraudCheckerProxy
(代理增强)
@Component("fraudCheckerProxy")
public class FraudCheckerProxy implements FraudChecker {@Autowired@Qualifier("realFraudChecker") // 指定真实对象private FraudChecker realFraudChecker;@Overridepublic void check(String userId) {long start = System.currentTimeMillis();System.out.println("【日志】准备执行欺诈校验逻辑");try {realFraudChecker.check(userId);System.out.println("【日志】欺诈校验完成");} catch (Exception e) {System.err.println("【异常报警】欺诈检查出错:" + e.getMessage());} finally {long duration = System.currentTimeMillis() - start;System.out.println("【监控】欺诈检查耗时:" + duration + "ms");}}
}
5.7. ✅ 测试类(模拟调用)
@Component
public class FraudCheckerRunner implements CommandLineRunner {@Autowired@Qualifier("fraudCheckerProxy") // 使用代理对象代替真实对象private FraudChecker fraudChecker;@Overridepublic void run(String... args) {fraudChecker.check("USER_123456");}
}
5.8. 🧪 启动类 Application.java
@SpringBootApplication
public class RiskApp {public static void main(String[] args) {SpringApplication.run(RiskApp.class, args);}
}
5.9. ✅ 输出结果:
【日志】准备执行欺诈校验逻辑
执行真实的欺诈检查逻辑,用户ID: USER_123456
【日志】欺诈校验完成
【监控】欺诈检查耗时:5ms
5.10. 📝 总结
要素 | 内容 |
场景 | 金融风控系统中对核心逻辑(欺诈校验)进行代理增强 |
模式 | 代理模式(静态代理,封装行为) |
优点 | 无需修改真实逻辑类,增强日志、监控、容错 |
Spring 集成 | 所有对象都由 Spring 管理,注解注入,无构造函数依赖 |
如需升级为 JDK 动态代理 或 Spring AOP 实现,可继续告诉我。也可以扩展为一组校验器链,支持责任链模式、组合增强等架构。
6. 原型设计模式思考
6.1. JDK 动态代理代理设计模式
目标:增强风控逻辑,例如记录日志、统计耗时、捕获异常等,不侵入真实业务代码。
6.1.1. 🔹 接口
public interface FraudChecker {void check(String userId);
}
6.1.2. 🔹 真实业务类(Spring 管理)
@Component
public class RealFraudChecker implements FraudChecker {@Overridepublic void check(String userId) {System.out.println("执行真实欺诈校验逻辑,用户ID: " + userId);}
}
6.1.3. 🔹 动态代理工厂类(Spring 管理)
@Component
public class FraudCheckerProxyFactory {@Autowiredprivate RealFraudChecker realFraudChecker;public FraudChecker getProxy() {return (FraudChecker) Proxy.newProxyInstance(FraudChecker.class.getClassLoader(),new Class[]{FraudChecker.class},(proxy, method, args) -> {long start = System.currentTimeMillis();System.out.println("【JDK代理】准备执行欺诈校验");try {return method.invoke(realFraudChecker, args);} catch (Exception e) {System.err.println("【JDK代理异常】" + e.getMessage());return null;} finally {System.out.println("【JDK代理】耗时:" + (System.currentTimeMillis() - start) + "ms");}});}
}
6.1.4. 🔹 测试调用类
@Component
public class ProxyRunner implements CommandLineRunner {@Autowiredprivate FraudCheckerProxyFactory proxyFactory;@Overridepublic void run(String... args) {FraudChecker proxy = proxyFactory.getProxy();proxy.check("USER_98765");}
}
6.2. Spring-AOP实现代理设计模式(推荐)
6.2.1. 🔹 业务接口 + 实现类(与上面一致)
public interface FraudChecker {void check(String userId);
}@Component
public class RealFraudChecker implements FraudChecker {@Overridepublic void check(String userId) {System.out.println("执行真实欺诈校验逻辑,用户ID: " + userId);}
}
6.2.2. 🔹 编写 AOP 切面类(增强逻辑)
@Aspect
@Component
public class FraudCheckerAspect {@Pointcut("execution(* com.example.riskcheck.FraudChecker.check(..))")public void checkPointcut() {}@Around("checkPointcut()")public Object aroundCheck(ProceedingJoinPoint pjp) throws Throwable {long start = System.currentTimeMillis();System.out.println("【AOP】开始风控校验");try {return pjp.proceed();} catch (Exception e) {System.err.println("【AOP异常】" + e.getMessage());throw e;} finally {long time = System.currentTimeMillis() - start;System.out.println("【AOP】校验耗时: " + time + "ms");}}
}
6.2.3. 🔹 测试调用类
@Component
public class AopRunner implements CommandLineRunner {@Autowiredprivate FraudChecker fraudChecker;@Overridepublic void run(String... args) {fraudChecker.check("USER_54321");}
}
6.2.4. 🔹 开启 AOP 支持(在启动类上)
@SpringBootApplication
@EnableAspectJAutoProxy
public class RiskApp {public static void main(String[] args) {SpringApplication.run(RiskApp.class, args);}
}
6.3. ✅ 输出示例(AOP方式)
【AOP】开始风控校验
执行真实欺诈校验逻辑,用户ID: USER_54321
【AOP】校验耗时: 7ms
博文参考
- 6. 代理模式 — Graphic Design Patterns
- 代理设计模式
相关文章:

设计模式——代理设计模式(结构型)
摘要 本文详细介绍了代理设计模式,包括其定义、结构组成、实现方式、适用场景及实战示例。代理设计模式是一种结构型设计模式,通过代理对象控制对目标对象的访问,可增强功能或延迟加载等。文中通过类图、时序图、静态代理、JDK动态代理、CGL…...
Elasticsearch的集群管理介绍
Elasticsearch 集群管理是确保分布式环境下系统稳定运行、高可用和高性能的关键。以下从集群架构、节点类型、故障转移到监控优化,全面解析 Elasticsearch 集群管理的核心要点: 一、集群架构与节点类型 1. 基本概念 集群(Cluster):由一个或多个节点组成,共同存储数据并…...
Spring MVC + Tomcat 8.5 踩坑实录:Servlet 版本引发的部署失败
🚧 Spring MVC Tomcat 8.5 踩坑实录:Servlet 版本引发的部署失败 🌐 作者:劲爽小猴头 🗓️ 时间:2025-05-28 📚 关键词:Spring MVC、Tomcat、Servlet、WAR部署、web.xml、Maven、JD…...

从“固定“到“流动“:移动充电如何重塑用户体验?
在传统充电模式中,"固定"不仅是技术的特征,更成为用户行为的枷锁——人们需要规划行程、寻找插座、等待电量填满,这种被动适配正在被移动充电技术颠覆。当充电设备从墙面解放,化身可携带的能源胶囊,甚至嵌入…...

玩客云 OEC/OECT 笔记(1) 拆机刷入Armbian固件
目录 玩客云 OEC/OECT 笔记(1) 拆机刷入Armbian固件玩客云 OEC/OECT 笔记(2) 运行RKNN程序 外观 内部 PCB正面 PCB背面 PCB背面 RK3566 1Gbps PHY 配置 OEC 和 OECT(OEC-turbo) 都是基于瑞芯微 RK3566/RK3568 的网络盒子, 没有HDMI输入输出. 硬件上 OEC 和 OECT…...
docker环境添加安装包持久性更新
1、进入docker 环境 2、安装新的安装包 pip install XXXX3、不要退出docker,新开终端,给当前环境从新打包更新镜像 docker commit ad6e1d2c5869 mynewpythonimagead6e1d2c5869是上面运行中的容器id, docker images 查看mynewpythonimage是新…...

GIS数据类型综合解析
GIS数据类型综合解析 目录 GIS数据类型综合解析1. 总体介绍2. GIS数据类型分类与对比2.1 主要数据类型对比表 3. 详细解析与扩展内容3.1 矢量数据(Vector Data)3.2 栅格数据(Raster Data)3.3 属性数据(Attribute Data&…...
VR 汽车:引领生产与设计的革命性飞跃
在汽车生产设计环节,VR 技术同样发挥着不可替代的重要作用。回首过去,设计师们设计一款新车时,面临着极为繁琐且艰巨的任务。首先,要绘制海量的图纸,从车辆的整体轮廓到每一个零部件的精细构造,都需用精准的…...

Prometheus + Grafana 监控常用服务
一、引言 Prometheus监控常见服务的原理主要包括服务暴露指标和Prometheus抓取指标。一方面,被监控服务通过自身提供的监控接口或借助Exporter将服务的性能指标等数据以HTTP协议的方式暴露出来;另一方面,Prometheus根据配置好的采集任务&…...

6月1日星期日今日早报简报微语报早读
6月1日星期日,农历五月初六,早报#微语早读。 1、10个省份城镇化率超70%,广东城镇人口超9700万; 2、长沙居民起诉太平财险不赔“新冠险”,立案878天后获胜判; 3、海口:全市范围内禁止投放互联…...
盲盒经济2.0:数字藏品开箱是否适用赌博法规
首席数据官高鹏律师团队编著 一、年轻人的“盲盒信仰”,法律的灰色地带 近年来,“盲盒经济”从实体玩具扩展到数字藏品领域,掀起了一波全民开箱热潮。年轻人在社交平台上晒出“开箱暴击”的喜悦,平台方则以“限量发行”“价值赋…...

如何在 Ubuntu 24.04 服务器上安装 Apache Solr
Apache Solr 是一个免费、开源的搜索平台,广泛应用于实时索引。其强大的可扩展性和容错能力使其在高流量互联网场景下表现优异。 Solr 基于 Java 开发,提供了分布式索引、复制、负载均衡及自动故障转移和恢复等功能。 本教程将指导您如何在 Ubuntu 24.…...

unity编辑器扩展dll形式展示
1.背景:最近搞工程迁移发现一旦c#报错就会导致编辑器菜单没法使用,做了一些尝试发现使用dll的方式会是不错的选择。当然有些工具还是建议用外部的c#工程来写比如winform. 2.遇到的问题:我记得之前2017年左右的时候做一个unity的dll工程并不需…...

vscode中launch.json、tasks.json的作用及实例
文章目录 launch.json是什么作用多环境调试简单实例进阶使用核心配置项解析调试第三方程序 launch.json是什么 顾名思义:它是在.vscode文件夹下的launch.json,所以是vscode启动调试的配置文件。总结:通过定义调试参数、环境变量和启动方式&a…...
UI自动化测试中的元素等待机制解析
目录 一、显式等待机制 二、隐式等待机制 三、强制等待机制 等待策略对比指南 在UI自动化测试中,元素定位失败通常由两种原因导致:页面存在iframe框架或未合理设置等待机制。本文重点解析三种等待策略及其应用场景。 一、显式等待机制 核心原理 通过…...

VScode编译调试debug,gpu的cuda程序,Nsight
进行下面操作的前提是,我们的环境已经能跑简单的CUDA程序了。 一、安装Nsight 二、创建launch.json文件 {"version": "0.2.0","configurations": [{"name": "CUDA C: Launch","type": "cuda-gdb…...

中企出海大会|打造全球化云计算一张网,云网络助力中企出海和AI创新
全球化是阿里云的长期战略,未来阿里云将持续加大云和 AI 基础设施建设投入。首先是加速打造全球化的云计算网络,一张具备 AI技术服务能力和全球竞争力的云计算网络是阿里云的长期目标。 —— 阿里巴巴集团 CEO、阿里云智能集团董事长兼 CEO 吴泳铭 5 月 …...
qwen-0.5b小模型的用处和显存要求
详细分析一下 Qwen-0.5B (5亿参数) 这个模型在不同训练阶段的显存需求以及它的用途。(根据网页反馈:1、0.5b做蒸馏,特定领域轻松超越sft的7b;2、大部分实时要求高的业务需要用小模型初筛降量,比如意图识别;…...

防范DDoS攻击,服务器稳定性崩溃的根源与高效防御对策
DDoS攻击(分布式拒绝服务攻击)已成为危害服务器稳定性和业务连续性的主要因素之一。本文将深入探讨为什么服务器一遇到DDoS攻击就崩溃,以及如何从根本上实现有效防御和应对这一威胁,帮助企业提升网络安全水平。 具体内容如下&…...

深入理解 SELinux:通过 Nginx 和 SSH 服务配置实践安全上下文与端口策略
目录 一、引言 二、实验环境说明 三、实验 1:Nginx 服务安全上下文配置 3.1 实验目标 3.2 操作步骤 1. 开启 SELinux 并重启系统 2. 安装 Nginx 并创建自定义目录 3. 配置 Nginx 指向自定义目录 4. 分析 SELinux 上下文冲突 5. 修改上下文为合法类型 6. 验…...

C++ —— STL容器——string类
1. 前言 本篇博客将会介绍 string 中的一些常用的函数,在使用 string 中的函数时,需要加上头文件 string。 2. string 中的常见成员函数 2.1 初始化函数 string 类中的常用的初始化函数有以下几种: 1. string() …...

用JS实现植物大战僵尸(前端作业)
1. 先搭架子 整体效果: 点击开始后进入主场景 左侧是植物卡片 右上角是游戏的开始和暂停键 <!DOCTYPE html> <html lang"en"> <head><meta charset"UTF-8"><meta name"viewport" content"widthdevic…...
Rust Mock 工具
Rust Mock 工具 Mock(模拟)是测试中不可或缺的工具,用来替代复杂或不可控的依赖,比如数据库、网络服务等,帮助我们写出高质量、健壮的测试代码。Rust 社区中,mockall 和 mockito 是两款主流且强大的 Mock …...
C++读写锁以及实现方式
文章目录 【C专题】读写锁(Reader-Writer Lock)原理与实现方式(含C11/20实践)一、读写锁核心概念1. **什么是读写锁?**2. **读写锁 vs 互斥锁** 二、C中的读写锁实现方式 方案一:POSIX 读写锁(p…...

Electron-vite【实战】MD 编辑器 -- 文件列表(含右键快捷菜单,重命名文件,删除本地文件,打开本地目录等)
最终效果 页面 src/renderer/src/App.vue <div class"dirPanel"><div class"panelTitle">文件列表</div><div class"searchFileBox"><Icon class"searchFileInputIcon" icon"material-symbols-light:…...

华为云Flexus+DeepSeek征文|华为云Flexus云服务器X实例上部署Dify:打造高效的开源大语言模型应用开发平台
目录 前言 1 Dify与华为云部署概述 1.1 什么是 Dify 1.2 华为云与 Flexus 云服务器的优势 2 云服务器部署 Dify 的步骤详解 2.1 模板选择 2.2 参数配置 2.3 资源栈设置 2.4 确认部署信息并执行 3 部署成功后的操作与平台使用指南 3.1 访问平台 3.2 设置管理员账号 …...
[git每日一句]Your branch is up to date with ‘origin/master‘
这句话是 Git 版本控制系统的提示信息,意思是: "你当前所在的分支已经与远程仓库(origin)的 master 分支同步,没有需要推送的提交。" 详细解释: Your branch - 指你当前所在的本地分支 is up …...

高密爆炸警钟长鸣:AI为化工安全戴上“智能护盾”
一、高密爆炸:一声巨响,撕开化工安全“伤疤” 2025年5月27日,山东高密友道化学有限公司的车间爆炸声,像一把利刃划破了化工行业的平静。剧烈的冲击波将车间夷为平地,黑色蘑菇云腾空而起,刺鼻的化学气味弥漫…...

机器人学基础——正运动学(理论推导及c++实现)
机器人正运动学 机器人正运动学一般是指从机器人的关节位置到基于参考坐标系下末端执行器的位置。 平移变换和旋转变换 平移变换 假设我们有两个坐标系A和B,坐标系A与B的方位相同,xyz轴的指向都是一致的,即没有旋转变换。有一点p…...

[网页五子棋][对战模块]处理连接成功,通知玩家就绪,逻辑问题(线程安全,先手判定错误)
文章目录 处理连接成功通知玩家就绪逻辑图问题 1:线程安全问题 2:先手判定错误两边都是提示:轮到对方落子 处理连接成功 实现 GameAPI 的 afterC…...