新闻详情

新闻详情

首页 / 资讯中心 / 详情

代理模式详解:控制对象访问的利器(静态代理 + JDK 动态代理)

发布时间:2026/10/3 12:35:27来源:尧图网络
代理模式详解:控制对象访问的利器(静态代理 + JDK 动态代理)
一、代理模式定义Proxy 模式是一种结构型模式。它为目标对象提供一个代理对象由代理对象控制对目标对象的访问。代理与目标实现相同的接口客户端只与代理打交道代理在调用目标前后可执行额外操作而不是单纯把请求转发出去。一句话想给某个对象加前置/后置处理鉴权、日志、缓存、事务又不想改它的业务代码就套一层代理。二、为什么需要代理模式动机访问控制目标对象不该直接暴露如远程服务、受限资源代理先做权限校验再决定是否放行。功能增强在目标方法前后统一织入日志、监控、事务等横切逻辑避免侵入业务代码。解耦客户端客户端依赖的是抽象接口目标对象可随时替换代理起到缓冲层作用。三、代理模式的结构角色与职责角色职责抽象主题Subject真实主题与代理主题的共同接口客户端面向它编程真实主题RealSubject被代理的目标对象真正执行业务逻辑代理Proxy持有 RealSubject 引用在转发请求前后执行额外操作持有«interface»SubjectsailBook()RealSubjectsailBook()ProxySubject-realSubject: RealSubjectsailBook()四、代码实现静态代理4.1 抽象主题与真实主题// 抽象主题publicinterfaceSubject{voidsailBook();}// 真实主题真正卖书的逻辑publicclassRealSubjectimplementsSubject{OverridepublicvoidsailBook(){System.out.println(卖书);}}4.2 静态代理publicclassProxySubjectimplementsSubject{privateRealSubjectrealSubject;// 持有真实对象publicProxySubject(RealSubjectrealSubject){this.realSubjectrealSubject;}OverridepublicvoidsailBook(){dazhe();// 调用前增强逻辑realSubject.sailBook();// 转发给真实对象give();// 调用后增强逻辑}privatevoiddazhe(){System.out.println(打折);}privatevoidgive(){System.out.println(代金卷);}}4.3 客户端publicclassMainClass{publicstaticvoidmain(String[]args){RealSubjectrealnewRealSubject();// 不用代理real.sailBook();// 使用代理客户端只面向 Subject不感知代理内部ProxySubjectproxynewProxySubject(real);proxy.sailBook();}}运行结果卖书 打折 卖书 代金卷关键点客户端面向Subject接口调用增强逻辑打折/代金券被收口在代理里真实主题RealSubject一行没改。五、静态代理的痛点为什么需要动态代理静态代理能跑但有硬伤代理类会膨胀接口里每多一个方法如buyBook、returnBook代理类都得手写一遍转发逻辑方法一多代理类变得又长又重复。增强逻辑无法复用打折/代金券这类增强写死在ProxySubject里换一个目标对象就要重写一个代理类。接口一改全改抽象主题增删方法真实类和代理类都得同步改。这些痛点催生了运行时由 JVM 自动生成代理类的动态代理。六、动态代理JDKJDK 动态代理靠三个要素协作要素作用接口Subject被代理的目标必须实现接口JDK 动态代理只代理接口InvocationHandler实现invoke(proxy, method, args)在真正调用前后织入增强逻辑Proxy.newProxyInstance(classLoader, interfaces, handler)运行时由 JVM 生成代理类字节码并返回实例6.1 通用处理器改进版笔记里的MyHandler直接持有RealSubject只能代理卖书这一种目标。实际应持有通用的Object target这样同一套增强可复用在任意实现了接口的对象上importjava.lang.reflect.InvocationHandler;importjava.lang.reflect.Method;publicclassMyHandlerimplementsInvocationHandler{privateObjecttarget;// 通用目标而非写死 RealSubjectpublicvoidsetTarget(Objecttarget){this.targettarget;}// proxy: 代理对象; method: 被调用的方法; args: 方法参数OverridepublicObjectinvoke(Objectproxy,Methodmethod,Object[]args)throwsThrowable{dazhe();// 反射调用真实对象的方法Objectresultmethod.invoke(target,args);give();returnresult;}privatevoiddazhe(){System.out.println(打折);}privatevoidgive(){System.out.println(代金卷);}}6.2 客户端importjava.lang.reflect.Proxy;publicclassMainClass{publicstaticvoidmain(String[]args){SubjectrealnewRealSubject();MyHandlerhandlernewMyHandler();handler.setTarget(real);// 运行时生成代理实例必须基于接口getInterfaces()Subjectproxy(Subject)Proxy.newProxyInstance(real.getClass().getClassLoader(),real.getClass().getInterfaces(),handler);proxy.sailBook();}}注意invoke里是method.invoke(target, args)——target是被代理的真实对象不是proxy本身若写成method.invoke(proxy, args)会引发自身无限递归。七、动态代理的局限与实战延伸局限只能代理接口。JDK 动态代理要求目标实现接口若目标没有接口需用CGLIB通过继承目标类生成子类代理Spring AOP 在目标无接口时自动切换到 CGLIB。Struts2 拦截器其核心思路就是动态代理——在 Action 调用前后织入拦截逻辑。Spring AOP底层正是 JDK 动态代理有接口时 CGLIB无接口时双实现事务、Transactional、日志都是这么织入的。MyBatis Mapper你只写了UserMapper接口没写实现类运行时 MyBatis 用动态代理生成实现并返回本质也是同一套路。八、应用场景与优缺点典型应用场景远程代理RPC 的 stub客户端像调本地方法一样调远程服务。虚拟代理懒加载图片/大对象先用占位代理真正用到时才加载真实资源。保护代理代理做权限校验无权限直接拦截。缓存 / 日志 / 事务代理AOP 场景。优点职责清晰增强逻辑收口在代理业务类保持纯净。符合开闭原则新增增强无需改动目标对象。解耦客户端只依赖抽象接口。缺点静态代理类会随接口膨胀动态代理可读性略降、调试稍难。JDK 动态代理受必须实现接口限制无接口需 CGLIB。调用链多一层性能有极微小损耗一般可忽略。九、总结代理模式 给目标对象套一层同接口的代理由代理控制访问、在调用前后织入增强属于结构型模式。三角色抽象主题Subject、真实主题RealSubject、代理Proxy。静态代理简单直观但类易膨胀JDK 动态代理InvocationHandlerProxy.newProxyInstance在运行时自动生成代理适合增强逻辑通用、目标多的场景。选型口诀有接口 → JDK 动态代理无接口 → CGLIB想加横切逻辑又不想改业务 → 上代理。一句话总结想给对象加戏又不动它的代码套一层代理——前置打折、后置代金券业务类压根不知道。
网站建设高端定制企业官网
RELATED

相关资讯

更多精彩内容,欢迎继续阅读

较早相关资讯

最新相关资讯

中望3D钣金:轮廓凸缘 2026/10/3 12:52:02

中望3D钣金:轮廓凸缘

首先创建一个基体平板,然后选择要创建非标准造型法兰的边。单击“编辑轮廓”按钮

阅读更多 →
苹果Mac电脑玩我的世界没有版本?用PCL-R即可! 2026/10/3 12:51:30

苹果Mac电脑玩我的世界没有版本?用PCL-R即可!

玩《我的世界》的 Mac 用户应该都懂这个痛点:PCL2 启动器原生只支持 Windows,官方没有 Mac 版本。 网上方案翻遍了,无非几种: 装 Parallels / VMware 虚拟机,开销巨大,M 芯片 Mac 发热严重、掉帧&#xff…

阅读更多 →
中望3D钣金:拉伸凸缘 2026/10/3 12:51:23

中望3D钣金:拉伸凸缘

该命令通过草图创建凸缘(支持开放和闭合草图)1.创建一个开放草图2.拉伸凸缘注意:若草图已有半径,半径选项将不生效.带闭合草图轮廓的拉伸凸缘注意:如果切口点是空白的,那么它将创建一个不能展开的封闭形状 …

阅读更多 →
LeetCode.1047.删除字符串中的所有相邻重复项 2026/10/3 12:50:05

LeetCode.1047.删除字符串中的所有相邻重复项

题目给出由小写字母组成的字符串 s,重复项删除操作 会选择两个相邻且相同的字母,并删除它们。在 s 上反复执行重复项删除操作,直到无法继续删除。在完成所有重复项删除操作后返回最终的字符串。答案保证唯一。就是用栈去遍历,碰上…

阅读更多 →
html学习第二天 2026/10/3 12:50:05

html学习第二天

1.ctrl shift /- 使vscode界面扩大/缩小 相对路径:相对于当前位置 2.本地绝对路径:src“E:/demo1/demo2/xxx.jpg” 3.网络绝对路径:src“图片地址,例如: https://i-blog.csdnimg.cn/direct/e7ea10edf06c4907a2ae713e0…

阅读更多 →
LeetCode.020.有效的括号 2026/10/3 12:49:18

LeetCode.020.有效的括号

题目给定一个只包括 (,),{,},[,] 的字符串 s ,判断字符串是否有效。有效字符串需满足:左括号必须用相同类型的右括号闭合。左括号必须以正确的顺序闭合。每个右括号都有一个对应的相同类型的左括…

阅读更多 →

今日资讯

本周资讯

本月资讯

看完文章仍有疑问?

联系尧图顾问,获取一对一建站咨询

立即免费咨询 📞 400-888-8888
📞 ✉