Java动态代理详解

动态代理自接触java以来便经常被提到,但过去始终没有深入研究,大多只是浅尝辄止。如今静下心来认真梳理其实现过程,才发现其原理并不晦涩难懂。通过亲自编写一个示例程序,基本掌握了它的核心机制与正确使用方式。只要肯投入时间去理解,并动手实践整个流程,掌握动态代理并非难事。

1、 动态代理的核心在于:根据目标对象a,动态生成一个与其对应的代理实例。

2、 该功能由JDK提供的java.lang.reflect包中的Proxy类实现,通过调用其静态方法完成代理对象的创建。

3、 此方法需要传入三个参数。

4、 第一个参数是类加载器,用于加载被代理类的字节码,可通过反射获取:a.getClass().getClassLoader()

立即学习“Java免费学习笔记(深入)”;

5、 第二个参数是接口数组,表示目标对象所实现的所有接口(不是方法列表),可通过a.getClass().getInterfaces()获得。

6、 第三个参数是调用处理器,需自定义一个类H并实现InvocationHandler接口,该接口中包含一个invoke方法,用来定义方法调用时的具体处理逻辑。

7、 h 是实现了InvocationHandler接口的实例。一旦获取了代理对象,任何对其方法的调用都会自动转发到 h 的 invoke 方法中,再由 invoke 内部将请求委派给原始对象 a 的对应方法执行。

Java动态代理详解

Java动态代理详解

8、 编写测试类,首先模拟无代理情况下的运行场景

9、 定义一个House类和IHouse接口。House类具有name属性,通过构造函数初始化,并实现buy方法以完成购房操作。

Java动态代理详解

Java动态代理详解

10、 创建一个人物类People,模拟“小明”这一角色,其中添加一个名为buyHouseByMyself的方法,用于描述个人直接购房的行为,不借助中介。

Java动态代理详解

11、 创建测试类TestDynamicProxy,在测试方法中声明一个名为“小明”的People对象和一个house实例,随后让小明调用buyHouseByMyself方法,执行自行购房流程。

12、 输出结果如下所示:

Java动态代理详解

Java动态代理详解

13、 接下来进行动态代理版本的测试

14、 创建一个名为 MyInvocationHandler 的类,实现 InvocationHandler 接口,并重写 invoke 方法。该类提供一个构造函数,接收一个 Object 类型的 target 参数,用于传入被代理的目标对象。通过此方式将目标对象注入处理器中,以便在方法调用时统一拦截并处理,从而实现灵活的方法增强。

15、 在 invoke 方法中,使用 method.invoke(target, args) 语句通过反射机制调用目标对象 target 上的方法 method,并传入参数 args,最终将返回结果赋值给 object 变量,完成动态方法调用。

eMart 网店系统 eMart 网店系统

功能列表:底层程序与前台页面分离的效果,对页面的修改无需改动任何程序代码。完善的标签系统,支持自定义标签,公用标签,快捷标签,动态标签,静态标签等等,支持标签内的vbs语法,原则上运用这些标签可以制作出任何想要的页面效果。兼容原来的栏目系统,可以很方便的插入一个栏目或者一个栏目组到页面的任何位置。底层模版解析程序具有非常高的效率,稳定性和容错性,即使模版中有错误的标签也不会影响页面的显示。所有的标

eMart 网店系统 0 查看详情 eMart 网店系统

16、 由于 MyInvocationHandler 构造函数接受的是 Object 类型,因此它可以适配任意类型的对象,具备高度通用性与扩展能力,适用于多种不同业务场景下的动态代理需求。

Java动态代理详解

Java动态代理详解

17、 完成 MyInvocationHandler 类后,即可着手获取代理对象。新建 ProxyClass 类,并定义 getDynamicProxy 方法用于生成动态代理实例,该方法接收一个 Object 类型的参数,代表需要代理的目标对象。

18、 该方法可为任意对象生成代理实例,具有良好的通用性。

19、 创建代理对象时,需先实例化 MyInvocationHandler 对象 handle,并将其作为参数传递给 Proxy.newProxyInstance 方法。此后,所有对代理对象 proxy 的方法调用,都将被重定向至 handle 的 invoke 方法中进行处理,从而实现方法的拦截与功能增强。

20、 另外两个参数分别是目标对象的类加载器及其所实现接口的集合。

21、 代理类创建完成后,开始测试通过代理完成购房的过程。

22、 在 People 类中新增一个 buyHouseByDynamicProxy 方法,接收一个 House 实例作为参数。

23、 在该方法中,通过 ProxyClass 获取 house 的代理对象 houseProxy,并调用其 buy 方法完成购房操作。

Java动态代理详解

24、 在 TestDynamicProxy 类中编写 testBuyHouseByProxy 测试方法,创建一个名为“小红”的 People 实例,调用 buyHouseByDynamicProxy 方法,利用动态代理机制完成购房流程,验证代理机制的有效性。

25、 成功通过代理对象调用了 House 的 buy 方法,输出结果显示调用链路正确执行。

Java动态代理详解

Java动态代理详解

26、 从本例可以看出,无论传入何种对象,只需调用 ProxyClass 的 getDynamicProxy 方法,即可快速获得其代理实例,无需关心具体类型,体现出极强的通用性和灵活性,极大简化了代理对象的创建过程,提升了代码复用率与系统可扩展性。

27、 相较于静态代理,动态代理的优势在于无需为每个被代理类单独编写代理类。在静态代理模式下,每新增一个被代理类就需要配套编写一个新的代理类,当数量庞大时会导致类爆炸,维护成本陡增。

28、 比如原本要分别定义 HouseProxy、FishProxy、CarProxy 等多个代理类,而采用动态代理后,仅需一个通用的 ProxyClass 即可满足所有对象的代理需求,避免了大量重复代码,显著优化了项目结构,增强了系统的可维护性与可拓展性。

29、 小明想要买房,于是通过代理找到中介,由中介代为办理相关事务,省时又省心。

30、 中介在帮小明购房的过程中可以额外做一些事情,这些行为就体现在 MyInvocationHandler 的 invoke 方法中,即在 method.invoke 前后插入自定义逻辑。

31、 利用动态代理机制,可以实现类似 Spring AOP 的功能,例如为方法添加事务控制,或在方法执行前后打印日志,从而集中管理横切关注点,提升系统的模块化程度。

以上就是Java动态代理详解的详细内容,更多请关注创想鸟其它相关文章!

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。
如发现本站有涉嫌抄袭侵权/违法违规的内容, 请发送邮件至 chuangxiangniao@163.com 举报,一经查实,本站将立刻删除。
发布者:程序猿,转转请注明出处:https://www.chuangxiangniao.com/p/895534.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
《活侠传》一修大师修改器使用方法说明
上一篇 2025年11月28日 17:31:16
MySQL数据检索+查询+全文本搜索_MySQL
下一篇 2025年11月28日 17:31:22

相关推荐

  • 降压超频(Undervolting)在笔记本与显卡上的能效提升

    降压超频是通过降低芯片核心电压来减少功耗与发热并维持性能的技术。现代处理器和显卡因制造差异,厂商通常设置较高默认电压以确保稳定性,而降压则在保证系统稳定的前提下,去除冗余电压,实现更低功耗与温度。其核心原理为:降低电压→减少功耗与发热→降低风扇转速与电池消耗→提升续航、静音性及持续性能表现。在笔记本…

    2026年9月22日
    200
  • Java TreeMap如何自定义排序规则

    TreeMap默认按键的自然顺序排序,可通过构造函数传入Comparator自定义排序规则。例如字符串可按长度排序:TreeMap map = new TreeMap((s1, s2) -> s1.length() – s2.length()); 对自定义对象如Person可按年龄…

    2026年9月22日
    000
  • Java Collections.synchronizedList方法如何保证线程安全

    synchronizedList通过同步方法保证线程安全,使用synchronized关键字对每个操作加锁,确保单个操作的原子性;但迭代或复合操作需手动同步,否则可能引发并发异常;其性能较低,适用于读多写少、并发不高的场景,高并发下推荐使用CopyOnWriteArrayList。 Java 中 C…

    2026年9月22日
    100
  • VSCode如何调试JavaScript代码 VSCode调试功能的实战技巧

    要在vscode中调试javascript,首先需设置断点、配置launch.json文件、选择合适的调试环境并启动调试会话;2. launch.json至关重要,常见陷阱包括program路径错误、type类型不匹配、cwd设置不当、混淆launch与attach模式以及source map配置缺…

    2026年9月22日
    000
  • 为什么建议手动定义Java序列化ID

    手动定义serialVersionUID可确保序列化兼容性,避免因类结构变化导致反序列化失败。Java默认生成的ID依赖类名、字段等信息,编译环境或代码微小改动均使其改变,易引发InvalidClassException。显式声明后,可在兼容性变更时主动控制ID更新,保留原ID则允许旧版本读取新对象…

    2026年9月22日
    200
  • 在Java中如何统计List中元素出现次数

    答案是使用Map或Stream API统计List元素频次最高效。通过HashMap手动遍历统计,或用Java 8的Stream结合groupingBy和counting()实现简洁计数,Collections.frequency适用于小数据量但性能较差,推荐Stream方式兼顾性能与可读性。 在J…

    2026年9月22日
    900
  • Java中如何区分逻辑错误和系统异常

    系统异常是程序运行中由JVM抛出的RuntimeException,如空指针、数组越界,会导致程序中断并打印堆栈;逻辑错误是程序语法正确但结果不符预期,如条件写反、循环次数错误,不会崩溃但行为异常。两者区别在于是否抛出异常、是否中断执行及调试方式不同,需通过防御性编程、单元测试和日志调试加以防范。 …

    2026年9月22日
    000
  • Spring Boot 应用中的单元测试、Mockito 和集成测试:最佳实践

    第一段引用上面的摘要: 本文旨在帮助初学者理解在 Spring Boot 应用中何时以及如何使用 JUnit、Mockito 和集成测试。我们将探讨这些测试框架在 Controller、Service 和 Repository 层中的应用,并提供示例说明何时使用 Mockito 模拟对象,以及何时使…

    2026年9月22日
    000
  • Karate框架中处理带方括号和日期范围的GET请求参数

    本文旨在解决Karate框架中构建包含复杂、带方括号(如filters[start_date])及日期范围的GET请求参数时遇到的URL编码问题。通过对比直接定义查询对象和使用param关键字的方法,详细阐述了如何正确地构造URL,确保参数格式符合预期,从而有效进行API测试。 1. 问题背景与挑战…

    2026年9月22日
    000
  • 日本科幻战斗飞行游戏《G-Rebels》实机宣传片

    日本科幻战斗飞行游戏《G-Rebels》实机宣传片日本科幻战斗飞行游戏《G-Rebels》实机宣传片日本科幻战斗飞行游戏《G-Rebels》实机宣传片日本科幻战斗飞行游戏《G-Rebels》实机宣传片

    日本开发商reakktor studios公开了飞行模拟游戏《g-rebels》的实机宣传视频,该作是一款开放世界战斗飞行模拟游戏,玩家可以一览《g-rebels》中活力四射和密集的城市群,从精英家园伊甸园到饱受战争蹂躏和被海啸淹没的城市威尼斯。 《G-Rebels》将登陆PC Steam平台,目前…

    2026年9月22日 用户投稿
    100
  • 家庭NAS搭建:硬件选型与RAID模式对传输速度的影响

    家庭NAS搭建需综合考虑CPU、内存、硬盘接口、网络和RAID模式。CPU至少四核,内存8GB起,推荐N5105/N100或AMD嵌入式处理器;千兆网口成瓶颈,应升级至2.5G/10G;SATA III限制SSD性能,建议支持NVMe主板。RAID 0提升速度但无冗余,RAID 1保障安全但写速低,…

    2026年9月22日
    100
  • Android自定义开关UI实现教程

    本文详细介绍了在Android应用中实现自定义开关UI的两种主要方法:一是通过集成第三方库如StickySwitch,快速实现美观且功能丰富的开关;二是通过结合Drawable XML和ToggleButton,实现高度定制化的开关外观。文章提供了详细的代码示例和配置说明,旨在帮助开发者灵活地创建符…

    2026年9月22日
    000
  • 在Java中如何对集合进行分区处理

    Java中集合分区是将大集合拆分为小集合,适用于并行处理、分页等场景;2. 可使用Guava库的Lists.partition()快速实现,但返回的是原列表视图,修改会影响原数据;3. 也可用Java 8 Stream结合IntStream和Collectors自定义分区,灵活性高;4. 按条件分区…

    2026年9月22日
    300
  • Karate教程:优雅处理GET请求中的复杂查询参数(含日期范围)

    本教程将详细介绍在Karate框架中如何正确发送包含复杂查询参数(特别是带有方括号的参数名,如filters[start_date])的GET请求。我们将通过实际示例,演示如何利用Karate的* param关键字优雅地构建URL,确保参数被正确编码并传递给后端服务,尤其适用于日期范围等场景。 理解…

    2026年9月22日
    200
  • Java项目中利用.class文件:Classpath配置与接口实现

    在Java项目中引用并实现来自.class文件的接口是常见的需求,尤其当仅提供编译后的字节码文件时。本文将深入讲解Java Classpath的核心概念及其重要性,并提供在命令行环境下配置Classpath的详细步骤和示例,确保编译器和JVM能够正确找到并加载所需的.class文件,从而顺利完成接口…

    2026年9月22日
    800
  • PHP何时需要同时flush_PHP同时使用flush和ob_flush原因

    先调用ob_flush()将PHP输出缓冲区内容推送到底层,再调用flush()通知服务器立即发送数据,两者配合可穿透PHP和服务器缓冲层,实现输出实时性。 在PHP开发中,flush() 和 ob_flush() 经常被一起调用,目的是为了让输出内容及时发送到浏览器,而不是被缓冲机制延迟。要理解为…

    2026年9月22日
    100
  • safari浏览器怎么阻止网站访问剪贴板_safari浏览器阻止网站访问剪贴板方法

    可通过关闭网站剪贴板权限、启用无痕浏览、禁用JavaScript或使用内容拦截扩展来阻止Safari网站访问剪贴板,保护隐私安全。 如果您在使用 Safari 浏览器时发现某些网站尝试自动读取或写入剪贴板内容,可能会导致隐私泄露或意外粘贴敏感信息。为防止此类行为,您可以采取以下措施限制网站对剪贴板的…

    2026年9月22日
    1900
  • Java算术运算符优先级解析

    算术运算符优先级决定Java表达式执行顺序,、/、% 高于 +、-,同级从左到右计算,括号可改变顺序,如 (5+3)2=16;整数除法需注意类型,5/2*3 结果为 6。 Java中的算术运算符优先级决定了表达式中各个运算的执行顺序。理解这些优先级规则,能帮助开发者正确编写和解读复杂的数学表达式。 …

    2026年9月22日
    900
  • PHP中操作JSON数组对象:添加与修改属性的实践指南

    本教程详细阐述如何在php中高效地处理包含对象的json数组。我们将学习如何利用`json_decode()`将json字符串转换为php数据结构,进而为数组中的现有对象添加或修改属性,并通过`json_encode()`将其转换回json字符串,避免手动构建json的常见错误。 在现代Web开发中…

    2026年9月22日
    1300
  • 机械键盘轴体深度手感分析:线性轴、段落轴与提前段落轴

    机械键盘手感取决于轴体类型,主流分为线性轴、段落轴和提前段落轴。线性轴直上直下顺滑连贯,代表如Cherry MX Red,适合游戏与快速输入;段落轴中程有明显阻力峰,提供清晰反馈,如Cherry MX Blue,适合文字工作;提前段落轴起步阻力大随后变轻,如TTC Gold Pink,防误触且节奏独…

    2026年9月22日
    000

发表回复

登录后才能评论
关注微信