发布时间:2026/7/13 5:45:45
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/7/13 5:40:45

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

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

2026/7/13 7:20:49

工业负载控制:TPD2017FN与PIC18F47K42的智能解决方案

1. 工业负载控制的核心挑战与解决方案在工业自动化现场,我经常遇到工程师们对电感和电阻负载控制的困惑。记得去年在东莞一家包装机械厂,他们的生产线频繁出现继电器触点烧蚀问题,每周都要停机更换。这正是典型的不当负载控制导致的后果。TPD…

2026/7/13 7:20:49

AI专著写作必备:精选AI工具,轻松打造20万字高质量专著!

AI专著写作:工具助力,高效创作 学术专著的价值在于其逻辑的严谨性,不过逻辑论证恰恰是写作过程中最容易出现问题的部分。AI写专著通常需要围绕一个核心观点进行系统性的探讨,既要对各个论点进行深入的阐述,又需要处理…

2026/7/13 7:20:49

5G NR FR1/FR2 频段对比:Sub-6GHz 与毫米波 3 大核心差异解析

5G NR FR1/FR2 频段对比:Sub-6GHz 与毫米波 3 大核心差异解析当5G技术从实验室走向商业部署时,频段选择成为网络规划中最关键的决策之一。目前全球运营商主要采用两种截然不同的频段策略:Sub-6GHz(FR1)和毫米波&#x…

2026/7/13 7:20:49

纽扣电池增强方案:NBM5100A与STM32L152的低功耗设计

1. 项目背景与核心挑战在物联网设备和便携式电子产品的设计中,纽扣电池(如CR2032、CR2025)因其紧凑的尺寸和稳定的性能成为众多低功耗设备的首选电源方案。然而这类电池存在两个固有缺陷:一是高内阻导致的脉冲负载能力不足&#x…

2026/7/13 7:20:49

C++生产级线程池实战:从锁竞争到优雅关闭的避坑指南

1. 项目概述:为什么一个“简单”的线程池能难倒老手?“不就是个任务队列加几个工作线程吗?” 这可能是很多C开发者看到线程池时的第一反应。确实,从概念上讲,线程池的核心逻辑清晰明了:预先创建一组线程&am…

2026/7/13 7:15:49

STM32L4A6ZG与AD7490构建高速多通道ADC采集系统

1. 项目概述:高速ADC与MCU的完美组合在工业自动化、医疗设备和测试测量等领域,模拟信号的精确采集与实时处理一直是核心需求。AD7490作为ADI公司推出的一款12位高速、低功耗16通道ADC,配合STM32L4A6ZG这款兼具高性能与低功耗特性的ARM Cortex…

2026/7/13 6:38:38

3步解锁音乐自由:ncmdumpGUI终极NCM文件解密转换指南

3步解锁音乐自由:ncmdumpGUI终极NCM文件解密转换指南 【免费下载链接】ncmdumpGUI C#版本网易云音乐ncm文件格式转换,Windows图形界面版本 项目地址: https://gitcode.com/gh_mirrors/nc/ncmdumpGUI 你是否曾在网易云音乐下载了心爱的歌曲&#…

2026/7/12 0:01:29

CANoe 19 SP3 配置 GB/T 27930-2023 A类系统:3步搭建BMS仿真测试环境

CANoe 19 SP3 配置 GB/T 27930-2023 A类系统:3步搭建BMS仿真测试环境随着新能源汽车行业的快速发展,充电通信协议的标准化和测试验证变得尤为重要。GB/T 27930-2023作为中国智能充电协议的最新版本,对充电机与电动汽车之间的通信提出了更严格…

2026/7/12 0:01:29

3步搞定RTL8852BE驱动:从零开始配置Wi-Fi 6网卡

3步搞定RTL8852BE驱动:从零开始配置Wi-Fi 6网卡 【免费下载链接】rtl8852be Realtek Linux WLAN Driver for RTL8852BE 项目地址: https://gitcode.com/gh_mirrors/rt/rtl8852be 还在为Linux系统无法识别RTL8852BE Wi-Fi 6网卡而烦恼吗?&#x1f…

2026/7/13 0:00:24

广氟 PTFE 高速线缆膜 —— 高端线缆绝缘材料新选择

PTFE高速线缆膜的基本概念与特点 PTFE 高速线缆膜是以聚四氟乙烯树脂为原料,经膨化双向拉伸制成的多孔绝缘薄膜,作为高速高频通信线缆的核心介质材料,内部形成均匀连通的微孔结构,兼具极低介电常数与介电损耗,能有效降…

2026/7/12 11:21:32

3个高效策略:快速掌握Axure中文界面配置

3个高效策略:快速掌握Axure中文界面配置 【免费下载链接】axure-cn Chinese language file for Axure RP. Axure RP 简体中文语言包。支持 Axure 11、10、9。不定期更新。 项目地址: https://gitcode.com/gh_mirrors/ax/axure-cn 还在为Axure RP的英文界面感…