深入解析代理模式:原理、实现与应用场景
1. 代理模式核心概念解析代理模式Proxy Pattern是结构型设计模式中最具实用性的模式之一它通过引入代理对象来控制对原始对象的访问。这种控制在软件开发中极为常见比如远程方法调用RMI的stub对象、Hibernate的延迟加载机制、Spring AOP的实现等本质上都是代理模式的应用。1.1 模式定义与基本结构代理模式的官方定义是为其他对象提供一种代理以控制对这个对象的访问。在实际编码中代理类和被代理类通常实现相同的接口客户端通过代理类间接访问被代理类。这种设计带来的直接好处是可以在不修改原始类代码的情况下通过代理类增加额外的功能逻辑。典型的代理模式包含三个核心角色Subject抽象主题声明真实主题和代理主题的共同接口RealSubject真实主题真正执行业务逻辑的具体类Proxy代理持有真实主题的引用控制对真实主题的访问// 抽象主题 interface Image { void display(); } // 真实主题 class RealImage implements Image { private String filename; public RealImage(String filename) { this.filename filename; loadFromDisk(); } private void loadFromDisk() { System.out.println(Loading filename); } Override public void display() { System.out.println(Displaying filename); } } // 代理 class ProxyImage implements Image { private RealImage realImage; private String filename; public ProxyImage(String filename) { this.filename filename; } Override public void display() { if (realImage null) { realImage new RealImage(filename); } realImage.display(); } }1.2 代理模式的五种常见类型根据使用场景和实现方式的不同代理模式可以分为以下几种主要类型虚拟代理Virtual Proxy延迟创建开销大的对象如图片懒加载。只有当真正需要时才创建真实对象优化系统资源使用。远程代理Remote Proxy为位于不同地址空间的对象提供本地代表。典型的如RPC框架中的stub对象隐藏了网络通信细节。保护代理Protection Proxy控制对原始对象的访问权限。常用于权限校验场景比如Spring Security的拦截机制。智能引用代理Smart Reference Proxy在访问对象时执行额外操作如引用计数、对象持久化等。C中的智能指针就是典型应用。动态代理Dynamic Proxy运行时动态生成代理类。Java中的java.lang.reflect.Proxy和CGLib都属于此类。提示在实际项目中动态代理的使用频率远高于静态代理因为它避免了为每个类手动编写代理类的繁琐工作。Spring框架的AOP功能就是基于动态代理实现的。2. 代理模式的实现方式详解2.1 静态代理实现静态代理是最基础的代理实现方式需要显式定义代理类。下面以文件加载为例展示完整实现// 文件加载器接口 public interface FileLoader { String load(String filePath); void save(String filePath, String content); } // 真实文件加载器 public class RealFileLoader implements FileLoader { Override public String load(String filePath) { System.out.println(Loading file: filePath); // 实际文件读取逻辑... return File content; } Override public void save(String filePath, String content) { System.out.println(Saving to file: filePath); // 实际文件写入逻辑... } } // 代理文件加载器添加权限校验 public class SecuredFileLoaderProxy implements FileLoader { private FileLoader fileLoader; private String userRole; public SecuredFileLoaderProxy(FileLoader fileLoader, String userRole) { this.fileLoader fileLoader; this.userRole userRole; } Override public String load(String filePath) { if (!checkAccess(read)) { throw new SecurityException(No read permission); } return fileLoader.load(filePath); } Override public void save(String filePath, String content) { if (!checkAccess(write)) { throw new SecurityException(No write permission); } fileLoader.save(filePath, content); } private boolean checkAccess(String operation) { // 简化版权限检查 return admin.equals(userRole) || (read.equals(operation) user.equals(userRole)); } }静态代理的优缺点非常明显优点实现简单容易理解缺点每个真实类都需要对应一个代理类当系统规模变大时会产生大量类文件2.2 动态代理实现动态代理通过在运行时生成代理类的方式解决了静态代理的缺点。Java提供了两种主要的动态代理机制2.2.1 JDK动态代理JDK动态代理基于接口实现使用java.lang.reflect.Proxy类创建代理对象public class LoggingInvocationHandler implements InvocationHandler { private Object target; public LoggingInvocationHandler(Object target) { this.target target; } Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { long start System.currentTimeMillis(); Object result method.invoke(target, args); long duration System.currentTimeMillis() - start; System.out.printf(Method %s executed in %d ms%n, method.getName(), duration); return result; } public static T T createProxy(T target, ClassT interfaceType) { return (T) Proxy.newProxyInstance( interfaceType.getClassLoader(), new Class?[]{interfaceType}, new LoggingInvocationHandler(target) ); } } // 使用示例 FileLoader loader new RealFileLoader(); FileLoader proxy LoggingInvocationHandler.createProxy(loader, FileLoader.class); proxy.load(/path/to/file);JDK动态代理的特点只能代理接口无需依赖第三方库性能较好相比CGLib2.2.2 CGLib动态代理CGLib通过继承方式实现代理可以代理普通类public class CglibLoggingInterceptor implements MethodInterceptor { Override public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable { long start System.currentTimeMillis(); Object result proxy.invokeSuper(obj, args); long duration System.currentTimeMillis() - start; System.out.printf(CGLib - Method %s executed in %d ms%n, method.getName(), duration); return result; } public static T T createProxy(ClassT targetClass) { Enhancer enhancer new Enhancer(); enhancer.setSuperclass(targetClass); enhancer.setCallback(new CglibLoggingInterceptor()); return (T) enhancer.create(); } } // 使用示例 RealFileLoader proxy CglibLoggingInterceptor.createProxy(RealFileLoader.class); proxy.load(/path/to/file);CGLib的特点可以代理普通类需要引入第三方库生成代理类的过程较慢但执行效率高不能代理final类和方法注意Spring框架在选择代理方式时遵循这样的规则 - 如果目标对象实现了接口默认使用JDK动态代理如果没有实现接口则使用CGLib。可以通过配置强制使用CGLib。3. 代理模式的高级应用场景3.1 在Spring框架中的应用Spring框架中代理模式的应用无处不在最典型的就是AOP面向切面编程的实现。Spring AOP使用代理模式来实现横切关注点如事务管理、日志记录等与业务逻辑的分离。Aspect Component public class TransactionAspect { Autowired private PlatformTransactionManager transactionManager; Around(annotation(org.springframework.transaction.annotation.Transactional)) public Object manageTransaction(ProceedingJoinPoint pjp) throws Throwable { TransactionStatus status transactionManager.getTransaction( new DefaultTransactionDefinition()); try { Object result pjp.proceed(); transactionManager.commit(status); return result; } catch (Exception e) { transactionManager.rollback(status); throw e; } } }Spring处理事务的典型流程检查方法是否有Transactional注解创建代理对象JDK或CGLib在方法调用前后添加事务管理逻辑委托给原始对象执行业务方法3.2 MyBatis中的延迟加载MyBatis使用代理模式实现关联对象的延迟加载Lazy Loading。当访问一个对象的关联属性时MyBatis会返回一个代理对象只有在真正访问关联对象属性时才会执行SQL查询。public class Blog { private Integer id; private String title; private Author author; // 关联对象 // getters and setters } // 配置延迟加载 resultMap idblogResultMap typeBlog association propertyauthor columnauthor_id selectselectAuthor fetchTypelazy/ /resultMap实现原理MyBatis创建Blog对象的代理通常是Javassist或CGLib当调用getAuthor()时代理对象检查是否已加载如果未加载执行预定义的SQL查询selectAuthor返回真实的Author对象3.3 RPC框架中的远程代理远程方法调用RPC框架如Dubbo、gRPC都大量使用代理模式。客户端通过接口调用方法时实际上调用的是本地代理对象stub代理对象负责将方法调用信息序列化并通过网络发送到服务端。// 定义服务接口 public interface UserService { User getUserById(long id); } // 客户端调用 UserService userService Proxy.newProxyInstance( UserService.class.getClassLoader(), new Class[]{UserService.class}, new RemoteInvocationHandler(user-service) ); User user userService.getUserById(123);远程代理的核心工作流程客户端调用代理对象方法代理对象将方法名、参数等序列化通过网络发送到服务端服务端反序列化并调用真实方法将结果序列化返回客户端代理对象反序列化结果并返回4. 代理模式的性能优化与实践技巧4.1 代理对象的缓存策略频繁创建代理对象会产生性能开销合理的缓存策略可以显著提升性能public class ProxyCache { private static final MapObject, Object proxyCache new ConcurrentHashMap(); SuppressWarnings(unchecked) public static T T getCachedProxy(T target, ClassT interfaceType) { return (T) proxyCache.computeIfAbsent(target, k - LoggingInvocationHandler.createProxy(k, interfaceType)); } }缓存策略选择建议对于无状态对象可以使用全局缓存对于有状态对象需要考虑线程安全问题缓存键设计通常使用目标对象接口类型的组合4.2 选择性代理方法不是所有方法都需要代理可以通过注解或配置实现选择性代理Target(ElementType.METHOD) Retention(RetentionPolicy.RUNTIME) public interface Loggable { } public class SelectiveInvocationHandler implements InvocationHandler { // ...其他代码 Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { if (method.isAnnotationPresent(Loggable.class)) { // 执行代理逻辑 long start System.currentTimeMillis(); Object result method.invoke(target, args); long duration System.currentTimeMillis() - start; System.out.printf(Method %s executed in %d ms%n, method.getName(), duration); return result; } // 直接调用原始方法 return method.invoke(target, args); } }4.3 代理链与责任链模式结合多个代理可以形成链式调用每个代理处理不同的横切关注点public class ChainedInvocationHandler implements InvocationHandler { private final ListInvocationHandler handlers; private final Object target; private int index 0; public ChainedInvocationHandler(Object target, ListInvocationHandler handlers) { this.target target; this.handlers new ArrayList(handlers); } Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { if (index handlers.size()) { return handlers.get(index).invoke(proxy, method, args); } return method.invoke(target, args); } } // 使用示例 ListInvocationHandler handlers Arrays.asList( new LoggingInvocationHandler(target), new TransactionInvocationHandler(target), new CacheInvocationHandler(target) ); FileLoader proxy (FileLoader) Proxy.newProxyInstance( FileLoader.class.getClassLoader(), new Class[]{FileLoader.class}, new ChainedInvocationHandler(target, handlers) );这种设计类似于Servlet Filter或Spring Interceptor可以实现各种横切关注点的灵活组合。5. 常见问题与解决方案5.1 代理对象导致的equals/hashCode问题当使用代理对象时equals和hashCode方法的行为可能会出乎意料RealFileLoader loader1 new RealFileLoader(); RealFileLoader loader2 new RealFileLoader(); FileLoader proxy1 createProxy(loader1); FileLoader proxy2 createProxy(loader2); System.out.println(proxy1.equals(proxy2)); // 可能返回false System.out.println(loader1.equals(loader2)); // 可能返回true解决方案在代理类中重写equals和hashCode委托给目标对象使用工具类比较非代理对象public static boolean equals(Object a, Object b) { if (a b) return true; if (a null || b null) return false; Object aTarget getTarget(a); Object bTarget getTarget(b); return aTarget.equals(bTarget); } private static Object getTarget(Object obj) { if (Proxy.isProxyClass(obj.getClass())) { InvocationHandler handler Proxy.getInvocationHandler(obj); if (handler instanceof TargetAware) { return ((TargetAware) handler).getTarget(); } } return obj; }5.2 循环依赖问题当代理对象相互引用时可能导致栈溢出public class ServiceA { Autowired private ServiceB serviceB; } public class ServiceB { Autowired private ServiceA serviceA; }解决方案使用setter注入代替字段注入配置Spring使用三级缓存解决循环依赖对部分bean禁用代理Scope(proxyMode ScopedProxyMode.NO)5.3 动态代理的调试技巧动态代理类在调试时难以跟踪可以采用以下技巧输出代理类名称System.out.println(proxy.getClass().getName()); // 输出类似com.sun.proxy.$Proxy0保存生成的代理类到文件仅JDK动态代理System.getProperties().put(sun.misc.ProxyGenerator.saveGeneratedFiles, true);使用Arthas等Java诊断工具检查代理类# 查看类继承关系 sc -d com.sun.proxy.$Proxy0 # 查看方法调用轨迹 trace com.sun.proxy.$Proxy0 *5.4 性能优化建议缓存代理类动态生成代理类开销较大应该缓存已生成的代理类减少代理层级避免多层代理嵌套如Spring AOP的多次代理选择性代理只为必要的方法添加代理逻辑使用轻量级字节码工具如ByteBuddy相比CGLib有更好的性能// ByteBuddy创建代理示例 Class? dynamicType new ByteBuddy() .subclass(Object.class) .method(ElementMatchers.named(toString)) .intercept(FixedValue.value(Hello World!)) .make() .load(getClass().getClassLoader()) .getLoaded();代理模式在实际项目中几乎无处不在从底层的RPC调用到上层的业务逻辑处理都能看到它的身影。掌握代理模式不仅能够更好地理解框架原理还能在需要扩展系统功能时提供灵活的解决方案。特别是在面对遗留系统改造时代理模式往往能在不修改原有代码的情况下实现功能增强这充分体现了开闭原则的价值。

相关新闻

StreamCap:3步解决跨平台直播录制难题的完整方案

StreamCap:3步解决跨平台直播录制难题的完整方案

StreamCap:3步解决跨平台直播录制难题的完整方案 【免费下载链接】StreamCap Multi-Platform Live Stream Automatic Recording Tool | 多平台直播流自动录制客户端 基于FFmpeg 支持监控/定时/转码 项目地址: https://gitcode.com/gh_mirrors/st/StreamCap …

2026/8/9 11:38:21 阅读更多 →
国产数据库性能监控探针升级实践与优化

国产数据库性能监控探针升级实践与优化

1. 项目背景与核心价值 POne性能测试平台作为企业级应用性能评估的核心工具,其监控探针的数据库兼容性直接影响着测试数据的完整性和准确性。近期完成的监控探针升级,新增了对东方通TongRDS和达梦DM8两款主流信创数据库的深度支持,这标志着国…

2026/8/9 11:38:21 阅读更多 →
QKeyMapper:免费开源按键映射工具,让Windows操作更高效

QKeyMapper:免费开源按键映射工具,让Windows操作更高效

QKeyMapper:免费开源按键映射工具,让Windows操作更高效 【免费下载链接】QKeyMapper [按键映射工具] QKeyMapper,Qt开发Win10&Win11可用,不修改注册表、不需重新启动系统,可立即生效和停止。支持游戏手柄映射到键鼠…

2026/8/9 11:38:21 阅读更多 →

最新新闻

深入解析Linux IO多路复用与Poll机制

深入解析Linux IO多路复用与Poll机制

1. 为什么我们需要IO多路复用? 想象你开了一家快餐店,只有一个服务员。传统的方式是,这个服务员每次只能服务一个顾客——点完单、等餐做好、上菜,全程盯着这一个顾客,其他顾客只能干等着。这种就是典型的阻塞IO模型&a…

2026/8/9 12:38:49 阅读更多 →
命运2单人模式解锁:3分钟掌握完全控制游戏体验的终极方案

命运2单人模式解锁:3分钟掌握完全控制游戏体验的终极方案

命运2单人模式解锁:3分钟掌握完全控制游戏体验的终极方案 【免费下载链接】Destiny-2-Solo-Enabler Repo containing the C# and XAML code for the D2SE program. Included is also the dependency for the program, and image asset. 项目地址: https://gitcode…

2026/8/9 12:38:49 阅读更多 →
QQ群爬虫工具完全指南:快速批量获取QQ群数据的终极方案

QQ群爬虫工具完全指南:快速批量获取QQ群数据的终极方案

QQ群爬虫工具完全指南:快速批量获取QQ群数据的终极方案 【免费下载链接】QQ-Groups-Spider QQ Groups Spider(QQ 群爬虫) 项目地址: https://gitcode.com/gh_mirrors/qq/QQ-Groups-Spider QQ群爬虫工具(QQ-Groups-Spider&a…

2026/8/9 12:38:49 阅读更多 →
DemoDay插件:AI自动化生成项目演示视频的完整指南

DemoDay插件:AI自动化生成项目演示视频的完整指南

如果你正在寻找一种能快速为你的项目生成演示视频的方法,并且希望这个过程足够智能、自动化,那么 DemoDay 这个 Claude 插件值得你花几分钟了解一下。它不是一个独立的桌面应用,而是一个深度集成在 Claude 平台中的插件,核心功能是…

2026/8/9 12:38:49 阅读更多 →
如何用Unlock-Music在浏览器中免费解锁加密音乐文件:终极完整指南

如何用Unlock-Music在浏览器中免费解锁加密音乐文件:终极完整指南

如何用Unlock-Music在浏览器中免费解锁加密音乐文件:终极完整指南 【免费下载链接】unlock-music 在浏览器中解锁加密的音乐文件。原仓库: 1. https://github.com/unlock-music/unlock-music ;2. https://git.unlock-music.dev/um/web 项目…

2026/8/9 12:38:49 阅读更多 →
AI模型迭代加速:从v4 pro到GPT-5/6的工程化实践指南

AI模型迭代加速:从v4 pro到GPT-5/6的工程化实践指南

这次我们来看一个关于 AI 模型迭代速度的讨论,核心是探讨当前 AI 能力(以“v4 pro”为代表)的惊人表现,并由此引发对下一代模型(如“GPT-5/6”)的想象。这并非一个具体的开源项目,而是一个普遍的…

2026/8/9 12:37:49 阅读更多 →

日新闻

5分钟告别提取码焦虑:baidupankey如何智能破解百度网盘资源锁

5分钟告别提取码焦虑:baidupankey如何智能破解百度网盘资源锁

5分钟告别提取码焦虑:baidupankey如何智能破解百度网盘资源锁 【免费下载链接】baidupankey 在线查询网盘提取码(维护中 rm repo) 项目地址: https://gitcode.com/gh_mirrors/ba/baidupankey 你是否曾经在深夜寻找一份重要资料&#x…

2026/8/9 0:01:47 阅读更多 →
如何快速生成中国车牌图片:Python开源工具完整指南

如何快速生成中国车牌图片:Python开源工具完整指南

如何快速生成中国车牌图片:Python开源工具完整指南 【免费下载链接】chinese_license_plate_generator 中国车牌生成器 项目地址: https://gitcode.com/gh_mirrors/ch/chinese_license_plate_generator 中国车牌生成器是一个基于Python的开源项目&#xff0c…

2026/8/9 0:01:47 阅读更多 →
收藏!小白程序员轻松入门大模型,从Harness工程开始实践

收藏!小白程序员轻松入门大模型,从Harness工程开始实践

文章强调学习大模型不应只关注模型本身,而应重视模型外的系统搭建,即Harness。提出AgentModelHarness的实用公式,详细介绍Harness的四个层次:持久化层、执行层、控制层和观察与验证层。文章还探讨了上下文工程、工具设计、AGENTS.…

2026/8/9 0:03:48 阅读更多 →

周新闻

5分钟告别提取码焦虑:baidupankey如何智能破解百度网盘资源锁

5分钟告别提取码焦虑:baidupankey如何智能破解百度网盘资源锁

5分钟告别提取码焦虑:baidupankey如何智能破解百度网盘资源锁 【免费下载链接】baidupankey 在线查询网盘提取码(维护中 rm repo) 项目地址: https://gitcode.com/gh_mirrors/ba/baidupankey 你是否曾经在深夜寻找一份重要资料&#x…

2026/8/9 0:01:47 阅读更多 →
如何快速生成中国车牌图片:Python开源工具完整指南

如何快速生成中国车牌图片:Python开源工具完整指南

如何快速生成中国车牌图片:Python开源工具完整指南 【免费下载链接】chinese_license_plate_generator 中国车牌生成器 项目地址: https://gitcode.com/gh_mirrors/ch/chinese_license_plate_generator 中国车牌生成器是一个基于Python的开源项目&#xff0c…

2026/8/9 0:01:47 阅读更多 →
收藏!小白程序员轻松入门大模型,从Harness工程开始实践

收藏!小白程序员轻松入门大模型,从Harness工程开始实践

文章强调学习大模型不应只关注模型本身,而应重视模型外的系统搭建,即Harness。提出AgentModelHarness的实用公式,详细介绍Harness的四个层次:持久化层、执行层、控制层和观察与验证层。文章还探讨了上下文工程、工具设计、AGENTS.…

2026/8/9 0:03:48 阅读更多 →

月新闻

免费解锁百度网盘SVIP加速:macOS用户必备的下载提速终极指南

免费解锁百度网盘SVIP加速:macOS用户必备的下载提速终极指南

免费解锁百度网盘SVIP加速:macOS用户必备的下载提速终极指南 【免费下载链接】BaiduNetdiskPlugin-macOS For macOS.百度网盘 破解SVIP、下载速度限制~ 项目地址: https://gitcode.com/gh_mirrors/ba/BaiduNetdiskPlugin-macOS 还在为百度网盘macOS版的龟速下…

2026/8/8 17:02:44 阅读更多 →
终极ncmdump指南:3分钟实现网易云NCM音乐解密与格式转换

终极ncmdump指南:3分钟实现网易云NCM音乐解密与格式转换

终极ncmdump指南:3分钟实现网易云NCM音乐解密与格式转换 【免费下载链接】ncmdump 项目地址: https://gitcode.com/gh_mirrors/ncmd/ncmdump 还在为网易云音乐下载的NCM格式文件无法在其他播放器播放而烦恼吗?ncmdump解密工具帮你轻松解决这个困…

2026/8/9 0:45:04 阅读更多 →
HarmonyOS 应用开发《掌上英语》第81篇: 智能体卡片:为英语学习 App 打造桌面级学习助手

HarmonyOS 应用开发《掌上英语》第81篇: 智能体卡片:为英语学习 App 打造桌面级学习助手

AgentCard 智能体卡片:为英语学习 App 打造桌面级学习助手适用平台:HarmonyOS 7.0 (API 26 Beta)一、引言 HarmonyOS 7.0(API 26 Beta)新增了 AgentCard 智能体卡片能力,这是继 HMAF(鸿蒙智能体框架&#x…

2026/8/8 17:02:44 阅读更多 →