java之动态代理

发布时间:2026/10/28 1:24:19

java之动态代理 目录[TOC](目录)前言1. 比喻理解2. 代码理解1. 签名2. 参数1ClassLoader loader (类加载器)3. 参数2Class?[] interfaces (接口数组)4. 参数3InvocationHandler h (调用处理器)3. 测试与运行4. 代理字节码原理总结前言通过一个通俗易懂的比喻快速理解 Java 动态代理的核心设计思想。通过手写 JDK 动态代理的完整代码详细剖析其核心参数与运行机制并深入 JVM 内存中的代理类字节码揭示动态代理的底层实现原理。1. 比喻理解例子大明星小美十分擅长唱歌和跳舞。打算举办演唱会举办演唱会的过程非常繁琐。小美只想把核心精力放在唱歌和跳舞上。代理小帅专门负责处理小美唱歌和跳舞之外的所有繁杂事务。赞助商希望小美来唱歌时不能直接和小美对话必须先和经纪人小帅交涉。调用过程小帅和赞助商谈妥后前置准备把小美带到舞台上小美只管唱歌核心业务。唱完歌后小帅还要负责结算收尾工作后置收尾。在这个过程中小帅就是小美的代理人也就是我们代码中常说的代理对象。2. 代码理解我们首先写一个接口叫做Star明星声明两个方法sing和dance。publicinterfaceStar{Stringsing(StringsongName);voiddance();}小美是大明星实现Star接口擅长sing与dancepublicclassBigStarimplementsStar{OverridepublicStringsing(StringsongName){System.out.println(小美正在唱songName);return谢谢大家;}Overridepublicvoiddance(){System.out.println(小美正在跳舞);}}接下来我们编写用于创建代理对象的工具类ProxyUtil。importjava.lang.reflect.InvocationHandler;importjava.lang.reflect.Method;importjava.lang.reflect.Proxy;publicclassProxyUtil{publicstaticStarcreateProxy(Starstar){return(Star)Proxy.newProxyInstance(ProxyUtil.class.getClassLoader(),//参数1newClass?[]{Star.class},//参数2newInvocationHandler(){//参数3OverridepublicObjectinvoke(Objectproxy,Methodmethod,Object[]args)throwsThrowable{if(sing.equals(method.getName())||dance.equals(method.getName())){System.out.println(找演唱会地点);Objectresultmethod.invoke(star,args);System.out.println(收尾);returnresult;}returnmethod.invoke(star,args);}});}}为了让代理对象正常工作Proxy.newProxyInstance必须明确以下三个参数1. 签名publicstaticObjectnewProxyInstance(ClassLoaderloader,Class?[]interfaces,InvocationHandlerh)2. 参数1ClassLoader loader (类加载器)在程序运行过程中动态代理会在内存中实时生成代理类的字节码。为了让 JVM 识别并加载该字节码需要提供一个类加载器。通常使用当前工具类的类加载器ProxyUtil.class.getClassLoader()或被代理类的类加载器。3. 参数2Class?[] interfaces(接口数组)此参数表示代理类要实现哪些接口。在我们的例子中代理要代替明星唱歌跳舞因此需要实现Star接口写为new Class?[]{Star.class}。4. 参数3InvocationHandler h (调用处理器)当外部调用代理对象的任何方法时都会转发到此处理器的invoke方法中执行。3. 测试与运行我们编写Main类进行测试publicclassMain{publicstaticvoidmain(String[]args){// 1. 创建真实对象BigStarbigStarnewBigStar();// 2. 创建代理对象StarproxyStarProxyUtil.createProxy(bigStar);// 3. 调用代理方法StringretproxyStar.sing(Lucky);System.out.println(ret);}}运行后控制台输出如下找演唱会地点 小美正在唱Lucky 收尾 谢谢大家4. 代理字节码原理看看代理对象的伪代码importjava.lang.reflect.InvocationHandler;importjava.lang.reflect.Method;importjava.lang.reflect.Proxy;importjava.lang.reflect.UndeclaredThrowableException;publicfinalclass$Proxy0extendsProxyimplementsStar{privatestaticMethodm1;// 代表 Object.equals()privatestaticMethodm2;// 代表 Object.toString()privatestaticMethodm3;// 代表 Star.sing()privatestaticMethodm4;// 代表 Star.dance()static{try{m1Class.forName(java.lang.Object).getMethod(equals,Object.class);m2Class.forName(java.lang.Object).getMethod(toString);m3Class.forName(Star).getMethod(sing,String.class);m4Class.forName(Star).getMethod(dance);}catch(Exceptione){thrownewNoSuchMethodError(e.getMessage());}}public$Proxy0(InvocationHandlerh){super(h);// 将处理器传递给父类 java.lang.reflect.Proxy}OverridepublicfinalStringsing(StringsongName){try{// 所有方法调用都会转发到超类持有的 InvocationHandler 的 invoke 方法中return(String)super.h.invoke(this,m3,newObject[]{songName});}catch(Error|RuntimeExceptione){throwe;}catch(Throwablet){thrownewUndeclaredThrowableException(t);}}Overridepublicfinalvoiddance(){try{super.h.invoke(this,m4,null);}catch(Error|RuntimeExceptione){throwe;}catch(Throwablet){thrownewUndeclaredThrowableException(t);}}}动态生成的代理类命名为$Proxy0它继承了java.lang.reflect.Proxy并且实现了目标接口Star。Java 不支持多重继承$Proxy0已经占用了继承Proxy的名额。所以只能代理接口无法代理实例化的类.$Proxy0的构造方法接收一个InvocationHandler h并通过super(h)传给父类Proxy统一保管。在重写的接口方法如sing、dance中没有包含任何业务逻辑而是直接调用super.h.invoke(this, method, args).总结动态代理的核心思想是解耦通过代理对象将繁琐的非核心业务与真实对象的核心业务隔离开来。JDK 动态代理利用java.lang.reflect.Proxy类的newProxyInstance方法在运行期动态地在内存中生成实现了指定接口的代理类字节码。代理类如$Proxy0继承自Proxy并实现目标接口其内部持有一个InvocationHandler对象所有接口方法的调用都会被重定向并转发到该处理器的invoke方法中执行。
延伸阅读

更多相关文章

2026/10/25 20:00:36

毕业必备!2026AI论文工具大盘点(覆盖 99% 毕业生论文需求)

本文精选13 款2026 年实测 AI 论文工具,按全流程全能型、垂直领域专精型、润色降重专家、文献管理助手四大类别排序,覆盖从选题到定稿全链路,适配本科 / 硕博 / 期刊全场景,附选型速查表与避坑指南,帮你快速找到最佳拍…

2026/10/28 1:22:18

艾尔登法环存档修改工具ER-Save-Editor完整指南

艾尔登法环存档修改工具ER-Save-Editor完整指南 【免费下载链接】ER-Save-Editor Elden Ring Save Editor. Compatible with PC and Playstation saves. 项目地址: https://gitcode.com/GitHub_Trending/er/ER-Save-Editor 艾尔登法环存档没法在游戏里直接改&#xff0c…

2026/10/28 1:22:18

.NET Word模板填充:合并域与合同批量生成实战

简介:面向 .NET 开发者的 Aspose.Words 模板建文档 Demo 源码,适合已具备 C# 基础、希望在未安装 Microsoft Word 的环境中批量生成信函、报告或合同的中级开发者。示例围绕模板占位符与邮件合并展开,涉及 Document 加载模板、MailMerge 注册…

2026/10/28 1:22:18

Java派单系统源码深度拆解:从后端架构到Android实战

简介:一套基于Java开发的派单系统完整项目,包含Android客户端源码与说明文档,面向服务行业订单分配场景(如外卖、家政),适合希望系统学习Java服务端与Android移动端全栈开发的初中级开发者。资源包共11019个…

2026/10/27 14:24:03

全国计算机二级C语言真题PDF高效刷题指南

简介:这份PDF是全国计算机二级C语言考试的试题与答案解析,专为备考二级C语言的考生准备。内容涵盖C语言特点与设计理念、程序基本组成单位、main函数执行流程、函数嵌套调用规则、标识符命名规范、整型实型字符型数据类型、八进制十六进制数合法形式、运…

2026/10/27 9:34:54

requests+BeautifulSoup:爬虫抓取h1标题的入门实战指南

简介:一份以实战为导向的Python爬虫入门资源,面向具备基本编程基础、希望快速掌握网络数据抓取的初学者,可解决从零编写简单爬虫的常见困惑。实例以requests库发送HTTP请求、BeautifulSoup解析HTML文档,完整演示从网页中提取 标题…

2026/10/27 0:59:21

递推最小二乘参数辨识MATLAB编程:二阶系统与渐消记忆实现

简介:这是一篇面向控制系统、信号处理与机器学习等领域学习者的最小二乘参数辨识程序说明文档。资源共包含一个docx格式文档,压缩包大小七十八KB,内容围绕递推最小二乘算法和渐消记忆最小二乘算法展开:先构造一个极点位于单位圆内…

2026/10/28 0:02:13

Python股票自动交易系统源码解析:从行情获取到风控的完整链路

简介:这份资源是面向高校计算机、金融相关专业毕业设计场景的完整项目源码包,主题为基于Python的股票自动交易系统,适合需要完成毕设选题、课程设计或自学金融量化交易开发的学生与开发者参考。压缩包共收录687个文件,整体约14.93…

2026/10/28 0:02:13

视酷酷信IM源码部署指南:Java 17+MySQL 8.0.33实战配置

简介:这是一套2024年亲测可部署的视酷酷信IM即时通讯系统源码,面向具备Java、OC、C#及Vue开发能力的技术人员,解决私有化即时通讯平台快速搭建与二次定制需求,尤其适用于需集成商城、保障数据主权的中小型企业或独立开发者。资源共…

2026/10/28 0:02:13

Python爬取百度迁徙数据:接口解析、批量采集与避坑指南

简介:这份资源是一个用Python爬取百度迁徙数据的脚本压缩包,面向具备Python基础、希望入门网络爬虫与数据解析的开发者,解决按日期获取全国热门城市人口迁徙数据的问题。包内共1个文件,为单个py脚本,压缩包约1KB&#…

还想了解更多?直接咨询顾问

免费诊断 + 免费方案 + 透明报价。

全国咨询热线400-8866-253
免费获取方案
☎咨询二维码 ☎ ↑