设计模式——代理设计模式(结构型)

article/2025/8/4 18:26:03

摘要

本文详细介绍了代理设计模式,包括其定义、结构组成、实现方式、适用场景及实战示例。代理设计模式是一种结构型设计模式,通过代理对象控制对目标对象的访问,可增强功能或延迟加载等。文中通过类图、时序图、静态代理、JDK动态代理、CGLIB动态代理、Spring代理等方式阐述实现方式,并结合金融风控场景进行实战示例,最后对比分析了JDK动态代理和Spring-AOP实现方式。

1. 代理设计模式定义

代理设计模式(Proxy Pattern)是一种结构型设计模式,它为其他对象提供一种代理以控制对这个对象的访问。代理对象在客户端和目标对象之间起到中介作用,常用于控制对象访问、增强功能或延迟加载等场景。代理模式为某对象提供一个替身或占位符,以控制对这个对象的访问。

1.1.1. 📌 结构组成:

角色

说明

Subject

抽象主题,定义目标对象和代理的共同接口。

RealSubject

真实主题,实现实际业务逻辑。

Proxy

代理对象,控制对真实主题的访问,可添加额外行为。

2. 代理设计模式结构

代理模式包含如下角色:

  • Subject: 抽象主题角色
  • Proxy: 代理主题角色
  • RealSubject: 真实主题角色

2.1. 代理设计模式类图

2.2. 代理设计模式时序图

3. 代理设计模式实现方式

代理设计模式的实现方式有多种,主要分为 静态代理动态代理(JDK 动态代理 & CGLIB 动态代理)。下面将依次介绍它们的实现方式及示例。

3.1. ✅ 静态代理(Static Proxy)

3.1.1. 🔧 实现步骤:

  1. 定义公共接口(抽象主题)
  2. 实现真实业务类(RealSubject)
  3. 编写代理类(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. 🔧 实现方式:

  1. 创建接口和实现类。
  2. 使用 InvocationHandler 实现增强逻辑。
  3. 通过 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 切面增强

@Aspect + @Around

JDK 或 CGLIB

事务管理

@Transactional

JDK 或 CGLIB

缓存注解

@Cacheable

Spring AOP 代理

3.5. 📝 代理设计模式总结

实现方式

是否要求接口

是否可增强所有方法

是否支持 final 类

静态代理

JDK 动态代理

CGLIB 动态代理

4. 代理设计模式适合场景

4.1. ✅ 适合使用代理模式的场景

场景

说明

权限控制

控制对敏感对象的访问,例如只有特定用户才能访问某些接口(安全代理)。

延迟加载

当对象创建成本高、初始化慢时,使用虚拟代理延迟加载资源(如图片、文件)。

远程代理(RPC)

客户端调用代理对象,本质是远程服务器的接口封装,例如 Dubbo、gRPC 等远程服务调用代理。

记录日志/监控行为

在调用真实对象前后执行附加操作(如日志、性能监控等),例如 AOP 的典型应用。

事务控制/缓存控制

拦截业务逻辑前后控制事务边界或缓存处理,常见于 Spring 中 @Transactional@Cacheable

SpringAOP实现原理

基于代理对 Bean 进行横切增强。

防止重复提交或频繁调用

通过代理封装防抖节流逻辑。

4.2. ❌ 不适合使用代理模式的场景

场景

原因

业务逻辑简单,不需增强行为

引入代理会增加结构复杂度,得不偿失。

不需要拦截/控制访问

如果只是调用普通方法,不涉及权限、监控等,直接使用原始对象更清晰高效。

频繁变动或高并发敏感场景

动态代理在高频调用下可能存在性能问题,不如直接调用来得高效。

需要访问类中 final

方法或类(JDK 动态代理)

JDK 动态代理只能基于接口,不能代理 final 方法或类;这时必须使用 CGLIB,但仍有限制。

不具备接口或无法继承的目标类

无法被 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
  • 代理设计模式

http://www.hkcw.cn/article/iYetnQacLi.shtml

相关文章

API网关性能测试与瓶颈定位:微服务世界的守门人之道

在现代微服务架构中,API网关(API Gateway)是所有外部请求进入系统的第一道关口,是服务路由、协议转换、安全认证、流量管控、熔断限流等功能的集中体现。它既是安全屏障,又是性能瓶颈的高发区。 性能测试中&#xff0c…

Vehicle HAL(2)--Vehicle HAL 的启动

目录 1. VehicleService-main 函数分析 2. 构建EmulatedVehicleHal 2.1 EmulatedVehicleHal::EmulatedVehicleHal(xxx) 2.2 EmulatedVehicleHal::initStaticConfig() 2.3 EmulatedVehicleHal::onPropertyValue() 3. 构建VehicleEmulator 4. 构建VehicleHalManager (1)初…

【科研绘图系列】R语言绘制论文组合图形(multiple plots)

禁止商业或二改转载,仅供自学使用,侵权必究,如需截取部分内容请后台联系作者! 文章目录 介绍加载R包数据下载导入数据数据预处理画图1画图2画图3画图4画图5系统信息介绍 这篇文章详细介绍了如何使用R语言进行科研绘图,特别是绘制论文组合图形(multiple plots)。文章从数…

设计模式——命令设计模式(行为型)

摘要 本文介绍了命令设计模式,这是一种行为型设计模式,用于将请求封装为对象,实现请求的解耦和灵活控制。它包含命令接口、具体命令、接收者、调用者和客户端等角色,优点是解耦请求发送者与接收者,支持命令的排队、记…

用提示词写程序(3),VSCODE+Claude3.5+deepseek开发edge扩展插件V2

edge扩展插件;筛选书签,跳转搜索,设置背景 链接: https://pan.baidu.com/s/1nfnwQXCkePRnRh5ltFyfag?pwd86se 提取码: 86se 导入解压的扩展文件夹: 导入扩展成功: edge扩展插件;筛选书签,跳转搜索,设置背景

一周学会Pandas2之Python数据处理与分析-Pandas2数据分组与聚合

锋哥原创的Pandas2 Python数据处理与分析 视频教程: 2025版 Pandas2 Python数据处理与分析 视频教程(无废话版) 玩命更新中~_哔哩哔哩_bilibili Pandas 的分组与聚合功能是数据分析的核心工具,允许你根据特定条件分割数据,然后对每个子集应…

零基础上手 Cherry Studio:打造专属 AI 助手的第一步

名人说:博观而约取,厚积而薄发。——苏轼《稼说送张琥》 创作者:Code_流苏(CSDN)(一个喜欢古诗词和编程的Coder😊) 目录 一、Cherry Studio是什么?为什么选择它?1.Cherry Studio简介…

API平台(API网关)之API编排

支持WEB可视化的API编排能力,内置基本组件、流程控制、报文转换以及其他类型的组件,通过可视化拖、拉、拽对API进行编排和调度,支持Restful API、WebService、JAVA等多协议转换混合编排和API服务聚合能力,满足复杂业务场景的API支…

初识PS(Photoshop)

初识PS(Photoshop) 1、Photoshop界面 2、常用快捷键

鸿蒙ArkTS | Badge 信息标记组件自学指南

在做 UI 设计时,我们经常会碰到这样一个需求:要在某个图标、按钮或列表项的角落加一个小小的提示,比如红点、新消息数量、状态标签之类的。这时候就轮到 ​​Badge​​ 组件登场了。 如果你想要一个简单优雅、可配置灵活的信息标记功能&…

【C++】cin和cout的性能问题讨论和优化方法

目录 1、背景知识2、ios::sync_with_stdio(false)2.1 **作用**2.2 原理2.3 注意事项 3、cin.tie(0)3.1 作用3.2 原理3.3 注意事项 4、代码演示5、实例操作5.1 创建数据文件5.2 进行代码演示 个人主页<—请点击 C专栏<—请点击 1、背景知识 在 C 中&#xff0c;标准输⼊输…

【数据结构】图的存储(十字链表)

弧节点 tailvex数据域&#xff1a;存储弧尾一端顶点在顺序表中的位置下标&#xff1b;headvex 数据域&#xff1a;存储弧头一端顶点在顺序表中的位置下标&#xff1b;hlink 指针域&#xff1a;指向下一个以当前顶点作为弧头的弧&#xff1b;tlink 指针域&#xff1a;指向下一个…

(二)微服务(grpc/grpc消费者)

文章目录 项目地址一、grpc介绍1.1 项目初始化1. 创建grpc项目2. 项目结构二、Discount grpc创建2.1 实体层1. Coupon实体2.2 Protos1. 创建discount.proto2. 配置proto3. 创建DiscountService4. Program里注册服务2.3 Seed 数据1. 创建表和Seed数据2. 自动migration2.4 更新Do…

机电的焊接技术

焊接技术:高温或高压条件下,使用焊接材料(焊条或焊丝)将两块或两块以上的母材(待焊接的工件)连接 成一个整体的操作方法&#xff61; 2.3.1 焊接设备和焊接材料的分类及选用 1.焊接设备&#xff08;对应焊接方法&#xff09; 2.焊接材料&#xff08;焊条、焊丝、焊剂、焊接气…

Ⅰ.计算机二级选择题(C语言概述)

【注&#xff1a;重点题以及添加目录格式导航&#xff01;&#xff01;&#xff01;】 【重点】&#xff08;第2题&#xff09; 【重点】&#xff08;第8题&#xff09; 【重点】&#xff08;第17题&#xff09; 【重点】&#xff08;第19题&#xff09; 【重点】&#xff08;第…

ck-editor5的研究 (4):初步使用 CKEditor5 的插件功能

前言 在上一篇文章中—— ck-editor5 的研究&#xff08;3&#xff09;&#xff1a;初步使用 CKEditor5 的事件系统和API &#xff0c;我们已经初步了解了 CKEditor5 的工作方式 那么这篇文章&#xff0c;我们将初步使用 CKEditor5 的插件功能&#xff0c;我将会写一个自己的…

分类预测 | Matlab实现CNN-LSTM-Attention高光谱数据分类

分类预测 | Matlab实现CNN-LSTM-Attention高光谱数据分类 目录 分类预测 | Matlab实现CNN-LSTM-Attention高光谱数据分类分类效果功能概述程序设计参考资料 分类效果 功能概述 代码功能 该MATLAB代码实现了一个结合CNN、LSTM和注意力机制的高光谱数据分类模型&#xff0c;核心…

嵌入式项目之mini2440系统制作烧写

系统移植的必要性与组成 在嵌入式开发中&#xff0c;**系统移植&#xff08;Linux 系统定制&#xff09;** 是常见的需求&#xff0c;主要原因在于&#xff1a; 1. **官方镜像体积过大**&#xff1a;标准 Linux 发行版&#xff08;如 Ubuntu&#xff09;可能占用数 GB 存储…

OpenShift AI - 启用过时版本的 Notebook 镜像

《OpenShift / RHEL / DevSecOps 汇总目录》 说明&#xff1a;本文已经在 OpenShift 4.18 OpenShift AI 2.19 的环境中验证 文章目录 查看可用 Notebook 镜像控制台查看命令行查看 Notebook 镜像和 Image Stream 对应关系启用老版本的 Notebook 镜像参考 查看可用 Notebook 镜…

“人单酬“理念:财税行业的自我驱动革命

引言&#xff1a;当薪酬不再是"固定数字"&#xff0c;而是"成长标尺" "为什么有人拼命工作却收入停滞&#xff1f;为什么企业总在人才流失中挣扎&#xff1f;"这些问题背后&#xff0c;往往隐藏着传统薪酬体系的僵化。而"人单酬"&…