Java: 深入理解动态代理

深入理解Java动态代理:机制、实现与应用 首先定义目标接口,并实现具体的业务逻辑类// 目标接口// 目标类(实现接口)@OverrideSystem.out.println("业务逻辑:添加用户 -> " + username);// 目标类(无接口)// 非final方法(CGLIB可重写)System.out.println("业务逻辑:创建订单 -> " + orderId);// final方法(CGLIB无法代理)System.out.println("取消订单 -> " + orderId); 阅读详情

代理模式

我们都知道代理人是干什么的,比如有一个歌手去开演唱会,但是有很多事情:卖门票、找赞助商、宣传。这些事情会让歌手去干吗,当然不会,这时候我们创建一个助理,让所有事情都去找助理,流程就会变成这样:助理卖门票,找赞助,宣传,那么最后唱歌呢,唱歌也找助理,只不过助理本身不会唱歌,助理只能回调歌手的唱歌方法,来找歌手唱歌,这就是代理模式。

那么代理模式有什么好处呢,通过上面我们发现好像有点AOP编程的意思了,直接可以在代理类中修改真正方法前后的业务逻辑。还有一个好处就是通过修改单个代理类,完成对整个项目的修改。

如一开始整个项目网络模型用的是hutool,写了一个hutool包装了GET方法,但是又想改成okhttp了,这样的话就得改所有用到hutool的地方。

但是用代理之后,只需要将代理类的模型将原来的hutool改为okhttp即可,相当于又封装了一层。

静态代理

根据描述,我们可以轻松的写出静态代理的代码,唱歌作为一个方法放在接口中,代理和歌手都实现这个接口并重写唱歌方法,代理类内部存一个歌手类,用来回调歌手唱歌方法。

public interface Ability {
    void sing();
}
public class Singer implements Ability{
    @Override
    public void sing() {
        System.out.println("歌手唱歌");
    }
}
public class SingerProxy implements Ability{
    private final Ability singer;

    public SingerProxy(Ability singer) {
        this.singer = singer;
    }

    @Override
    public void sing() {
        //这里执行业务逻辑
        System.out.println("代理卖票");
        singer.sing(); // 回调真实对象的sing方法
    }
}
public class Run {
    public static void main(String[] args) {
        Ability singer = new Singer();  // 真实对象
        Ability singerProxy = new SingerProxy(singer); // 代理对象
        singerProxy.sing();
    }
}

结果:

这就是静态代理,思路简单,方便实现。有缺点:如果现在又来了个跳舞的,就得写一个跳舞的代理这样就会出现好多好多代理类。

解决办法:动态代理!

动态代理

动态代理是在代码运行阶段动态创建的代理类,将创建的代理类的字节码文件加载到JVM虚拟机中,相当于是在运行前没有创建代理类,而运行时是动态代理机制帮我们创建的,这个类不是显式的,所以看不到。

使用方法:

还是拿刚才的例子进行改造,动态代理就不需要我们自己再创建代理类了。

于是我们的主函数就改成了:

public class Run {
    public static void main(String[] args) {
//        Ability singer = new Singer();
//        Ability singerProxy = new SingerProxy(singer);
//        singerProxy.sing();


        Ability singer = new Singer();
        Ability singerProxy = (Ability) Proxy.newProxyInstance( // 代理对象
                Run.class.getClassLoader(),
                new Class[]{Ability.class},
                new InvocationHandler() {
                    @Override
                    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
                        System.out.println("代理卖票");
                        return method.invoke(singer, args);
                    }
                }
        );

        singerProxy.sing();
    }
}

看不懂没有关系,我们接下来讲原理就懂了。

先说使用方法:主要使用到了Proxy.newProxyInstance() 方法创建出来了代理类,来看一下源码中需要传入的参数

第一个参数传一个类加载器,这里可以通过其他类的class获取加载器,也可以通过当前类的class获取,他们指向的其实都是一个加载器,这是JVM的内容。会用即可。

第二个参数要求传一个接口列表,也就是想代理哪些接口,实例化出的目标就可以用这些接口接收

第三个是传一个处理器,这个处理器里面只需要重写一个invoke方法,这个方法也就是我们真正的代理方法了。它又有三个参数,第一个不常用,指向代理对象本身,第二个是反射出来的方法。指的是某个类的方法而不是实例的具体方法,这个要搞清楚,例如:调用代理对象的sing方法后,method指代的只是sing这个方法而已,如果想要调用真实对象的方法就要调用该方法里的method.invoke(singer, args),这样就能执行singer它自己的sing方法了。第三个参数是调用者传过来的参数列表,不懂看下边这张图

简单来说就是代理对象在调用方法时回调了我们重写的invoke方法,并将参数携带过来了。

所以我们执行sing方法后先打印"代理卖票"这句话。

下面我们往下追newProxyInstance这个方法的源码:

点进去我们发现它用了一个构造器来构造,接着我们看构造器如何来的

我们看到了ProxyBuilder,接着往下追 

进到build方法里,这里有一个defineProxyClass创建了一个类,通过这个类拿到构造器返回,我们看一下这个类怎么来的

下面这个方法有点长,我们直接看return部分

这里生成了一个字节数组,也是通过这个字节数组生成了类。我们就不再往下追了,下面就是一些偏底层的字节码生成,我们只需知道这个对象是由ProxyGenerator构造了一个字节数组,把字节数组转为类的class,通过class的构造器构造出类的对象。

 由于ProxyGenerator.generateProxyClass() 这个方法在最新的JDK中不然调用了,我就生成不了这个类的class文件来观察了,所以我让豆包生成了一份代理对象的class文件长什么样供参考:

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.lang.reflect.UndeclaredThrowableException;

// 动态生成的代理类,实现了目标接口Subject
public final class $Proxy0 extends Proxy implements Ability {
    // 静态方法缓存(存储接口中的方法)
    private static Method m1;  // Object类的equals方法
    private static Method m3;  // Subject接口的Sing方法
    private static Method m2;  // Object类的toString方法
    private static Method m0;  // Object类的hashCode方法

    // 构造方法,接收InvocationHandler
    public $Proxy0(InvocationHandler h) throws  {
        super(h);
    }

    // 重写equals方法
    public final boolean equals(Object obj) throws  {
        try {
            return (Boolean)super.h.invoke(this, m1, new Object[]{obj});
        } catch (RuntimeException | Error e) {
            throw e;
        } catch (Throwable t) {
            throw new UndeclaredThrowableException(t);
        }
    }

    // 实现Ability接口的Sing方法
    public final void Sing() throws  {
        try {
            // 核心:通过InvocationHandler调用
            super.h.invoke(this, m3, (Object[])null);
        } catch (RuntimeException | Error e) {
            throw e;
        } catch (Throwable t) {
            throw new UndeclaredThrowableException(t);
        }
    }

    // 重写toString方法
    public final String toString() throws  {
        try {
            return (String)super.h.invoke(this, m2, (Object[])null);
        } catch (RuntimeException | Error e) {
            throw e;
        } catch (Throwable t) {
            throw new UndeclaredThrowableException(t);
        }
    }

    // 重写hashCode方法
    public final int hashCode() throws  {
        try {
            return (Integer)super.h.invoke(this, m0, (Object[])null);
        } catch (RuntimeException | Error e) {
            throw e;
        } catch (Throwable t) {
            throw new UndeclaredThrowableException(t);
        }
    }


    // 静态代码块,初始化方法缓存
    static {
        try {
            m1 = Class.forName("java.lang.Object").getMethod("equals", Class.forName("java.lang.Object"));
            m3 = Class.forName("Subject").getMethod("Sing");
            m2 = Class.forName("java.lang.Object").getMethod("toString");
            m0 = Class.forName("java.lang.Object").getMethod("hashCode");
        } catch (NoSuchMethodException e) {
            throw new NoSuchMethodError(e.getMessage());
        } catch (ClassNotFoundException e) {
            throw new NoClassDefFoundError(e.getMessage());
        }
    }
}
    

简单说就是生成的这个类实现了我们刚才给他传入的接口,并且重写了方法,具体方法操作就是回调我们刚才在动态代理重写的invoke方法。 动态代理的原理我们就讲完了。下面的Retrofit也是动态代理典型的使用场景。

滚雪球学Java(25):Java动态代理:深入理解AOP编程的基石 🏆本文收录于「滚雪球学Java」专栏,专业攻坚指数级提升,助你一臂之力,带你早日登顶🚀,欢迎大家关注&&收藏!持续更新中,up!up!up!! 阅读详情

相关推荐

详解ReID的各部分组成及Trick——基于FastReID

这一系列博客将基于京东开源的FastReID进行扩充,详细介绍了ReID的各个组成部分,一些有用的Trick,评价指标,常用数据集等,详细内容见下方的链接,总结不易,如有理解不正确之处,麻烦各位批评指正。 一、FastReID的中的baseline文件配置 二、Training strategy 三、Pre-processing 四、Backbone 五、Aggregation 六、Head 七、Loss 八、Distance Metric 九、Post-processing 十、Evaluation 十一

藏晖的博客 9163

深入理解:Java动态代理

动态代理是java中非常重要的一种技术,很多框架的底层实现都使用到了动态代理,例如dubbo、spring、jdbc的事务控制等,因此掌握动态代理的使用并深入理解是非常必要的。 动态代理,顾名思义,来自于Java设计模式中的代理模式: 代理模式:给某一个对象提供一个代理,并由代理对象来控制对真实对象的访问。代理模式是一种结构型设计模式。 代理模式的结构比较简单,其核心是代理类,为了让客户端能够一致性地对待真实对象和代理对象,在代理模式中引入了抽象层。 代理模式根据字节码文件的创建时机可以分为静态代理和动

qq_38001359的博客 281

SWMM建模与案例应用

4、排水系统控制规则通过控制功能,可以在模拟进行过程中,通过条件判断,对闸门、水泵、管道、孔口、堰进行控制,实现排水系统实时控制。5、SWMM与其他模型对比分析分析:STORM、MOUSE、Info Works、SUSTAIN、SWC。1、模型初始设置主要参数:雨量计、汇水区、节点、出水口、管渠、分流器、蓄水池等参数前缀的设置。2、气象数据设置温度、蒸发、风速、融雪、面积亏损、气候调整、雨量计。1、多软件数据交互:CAD、Arcgis、SWMM。(1)节点、管段、水泵、孔口、堰、雨水口和街道。

m0_74575633的博客 3417

深入理解java的动态代理:JDK动态代理和CGlib动态代理

动态代理机制作为JavaSE的重要知识点和Spring框架中AOP切面编程的核心实现机制, 本文从两种动态代理来出发, 深入理解动态代理机制.本文介绍了java的动态代理机制, 分析了基于JDK的动态代理和基于CGlib的动态代理机制.

m0_62407503的博客 938

Kaggle时间序列竞赛金牌方案解析与实战指南

本文深度解析了Kaggle时间序列竞赛的金牌方案,揭示了其成功不仅依赖先进模型,更在于系统工程思维。文章系统阐述了从数据理解、特征工程到模型集成与后处理的全流程,并重点剖析了分层建模、自定义损失函数、时序交叉验证等核心技巧,为参赛者提供了从理论到实战的完整指南。

weixin_29196315的博客 355

SAP 货币类型和公司代码的货币设置

货币类型分为公司代码和集团货币,一般FI 10类型和集团货币 30,事务代码是8KEM; 设置货币类型的事务代码是OB22 在S/4 1809版本里编辑功能统合到事务代码FINSC_LEDGER 中了,这里集中了分类账和公司代码的设置; 设置多账簿的币种(会出现在BSEG和FAGLFLEXA表中) 汇率维护在TCURR表中,可通过BAPI_EXCHANGERATE_GETDETAIL函数获取。 CO货币的事务代码是成本控制范围货币:OKKP ,一般设置为货币码20和30; 另外, SCC4设置集团货币,

RichardYang2020的博客 1万+

Java动态代理:深入理解与实践

本文深入介绍了Java动态代理的实现原理与应用,包括基于Proxy类和InvocationHandler接口的JDK动态代理实现步骤,以及面向未实现接口类的CGLIB代理方案。动态代理通过运行时生成代理类,实现了日志记录、事务管理等横切关注点的统一管理,具有灵活性和非侵入性特点,但也存在性能开销和接口依赖的局限性。文章还对比了两种代理方式的优缺点,为AOP编程提供了实用技术参考。

软件科学-郝学胜 1104

Claude Code 学习笔记之一:理解 Agentic Loop 与内置工具

本文介绍了Claude Code这一终端智能助手的工作原理与使用方式。作者从ABAP开发经验出发,指出学习Claude Code的高级用法具有长期价值。文章详细解析了Claude Code的Agentic Loop机制:通过大语言模型进行推理,借助各类工具执行任务,并循环收集上下文、执行操作、验证结果三个步骤。系统阐述了Claude Code支持的五大类工具及其扩展方式,说明了其访问本地资源的范围和自治处理能力,同时介绍了权限模式等安全机制。最后提供了从小任务开始、充分探索、及时引导、使用CLAUDE.md

2007 年 ~ 2025 年,深耕 SAP 技术 18 年 546

【Java】深入理解动态代理:JDK、CGLIB

代理模式 日常生活中代理司空见惯的,比如某地区总代理,直白点就是中间商。在代码的世界里也有这种“中间商”,不过这个“中间商”不收差价,有时候甚至给你点额外的小惊喜。 ...

beFocused的博客 373

1、vectorCast单元测试常用操作

进入软件主页面,点击file,选择set working directory,随便选择一个保存该项目的目录即可。

weixin_59334478的博客 2156

MFC实现图书管理系统(附完整源码)

MFC实现图书管理系统(附完整源码)

希望我的博客,能帮上你解决学习中工作中所遇到的问题 800

深入理解Java动态代理:JDK代理与CGLIB代理全面解析

本文深入解析Java动态代理技术,包括JDK动态代理和CGLIB动态代理。代理模式通过中介对象控制访问,在不修改原代码的情况下添加额外功能。JDK动态代理基于接口,使用Proxy和InvocationHandler实现;CGLIB通过继承生成子类代理,适用于无接口类且性能更优。文章对比了两种代理的优缺点、适用场景和实现步骤,帮助开发者理解核心技术原理,为学习Spring框架奠定基础。动态代理是框架设计的核心,能有效提升代码复用性和灵活性。

凉伊的博客 1002

(4-2)A*

实际已经花费的代价(g(n)):从起点到当前节点n的实际路径代价。启发式估计的剩余代价(h(n)):从当前节点n到目标节点的估计路径代价。这是A算法的关键之一,启发式函数要足够接近实际代价,但又要高效计算。如果启发式函数等于0,A算法就相当于Dijkstra算法。实现A*算法的核心步骤如下所示。(1)初始化:将起点加入开放列表(open list),并将其f值设为g值和h值的和。(2)循环:从开放列表中选择具有最小f值的节点作为当前节点。如果当前节点是目标节点,算法结束;

码农三叔 1806

深入理解 Java 代理:静态代理与动态代理剖析

在 Java 编程领域,代理模式是一种常见且重要的设计模式。它通过引入代理对象,实现对目标对象的访问控制和功能增强。Java 中的代理主要分为静态代理和动态代理,它们在实现方式和应用场景上各有特点。本文将深入探讨 Java 代理的相关知识,重点分析静态代理与动态代理的区别,并详细讲解动态代理的原理与实现。

2401_84910501的博客 1322

IMSL CNL 7.0.0 (x86-64)Crack

IMSL CNL 7.0.0 (x86-64)Crack intel的算法库破解文件,这是C++版本的破解文件

精雕软件(JDpaint) 5.5 绿色版

精雕软件(JDpaint) 5.5 绿色版精雕软件(JDpaint) 5.5 绿色版精雕软件(JDpaint) 5.5 绿色版

百度T7:深入理解Java动态代理与代码模拟JDK实现动态代理【JAVA核心】

一、概述 1. 什么是代理 我们大家都知道微商代理,简单地说就是代替厂家卖商品,厂家“委托”代理为其销售商品。关于微商代理,首先我们从他们那里买东西时通常不知道背后的厂家究竟是谁,也就是说,“委托者”对我们来说是不可见的;其次,微商代理主要以朋友圈的人为目标客户,这就相当于为厂家做了一次对客户群体的“过滤”。我们把微商代理和厂家进一步抽象,前者可抽象为代理类,后者可抽象为委托类(被代理类)。通过使用代理,通常有两个优点,并且能够分别与我们提到的微商代理的两个特点对应起来: 优点一:可以隐藏委托类的实现; 优

Java_Pluto的博客 196

LinePhone3.2.7(android端最新版本) sip客户端

SIP客户端For android:LinePhone3.2.7(最新版本),官网地址:http://www.linphone.org/

MODBUS RTU从站调试实战:帧格式、CRC16与踩坑记录

在工业自动化领域,设备通信协议是连接PLC、传感器与上位机的桥梁。MODBUS作为应用最广泛的串行通信协议之一,以主从架构和简洁帧结构著称,尤其以RTU模式在RS485总线上应用最为普遍。理解其寄存器模型、功能码以及CRC16校验原理,是嵌入式工程师实现可靠数据采集与控制的基础。CRC校验能够有效对抗工业现场电磁干扰,而RS485收发时序与地址偏移处理则直接影响通信稳定性。从温湿度采集板到智能电表,从物联网关到PLC扩展模块,MODBUS RTU几乎覆盖了所有工业设备联网场景。本文从协议原理出发,结合从站固

weixin_34279579的博客 453

Data-Structures-and-Algorithm-Analysis-in-Java.pdf

作者: Weiss, Mark A. 出版社: Addison Wesley Data Structures and Algorithm Analysis in Java is an “advanced algorithms” book that fits between traditional CS2 and Algorithms Analysis courses. In the old ACM Curriculum Guidelines, this course was known as CS7. This text is for readers who want to learn good programming and algorithm analysis skills simultaneously so that they can develop such programs with the maximum amo...

【Java】深入理解 Java 动态代理:JDK 与 CGLIB 的原理、区别及实战示例

在 Java 开发中,动态代理是实现 AOP、事务控制、日志拦截等核心功能的关键技术。本文全面对比了 JDK 动态代理与 CGLIB 动态代理的实现原理、适用场景、性能差异及限制条件,并提供完整可运行的代码示例。通过本文,你将掌握如何根据项目需求选择合适的代理方式,并深入理解 Spring 等框架背后的代理机制。

Syals的博客 157

深入理解 Java 代理:从静态代理到动态代理的完整指南

代理模式(Proxy Pattern)是 Java 中一种重要的设计模式,它通过创建一个代理对象来控制对原始对象的访问。代理对象在客户端和目标对象之间起到中介作用,可以在不修改目标对象代码的情况下,增加额外的功能或控制访问。代理模式的核心价值访问控制:控制客户端对真实对象的访问权限功能增强:在不修改原对象代码的情况下添加新功能延迟加载:只有在真正需要时才创建或加载目标对象简化客户端:客户端只需与代理对象交互,无需了解复杂的实现细节。

yexianglunbai的博客 206

Spring的两种动态代理:Jdk和Cglib 的区别和实现

一、原理: java动态代理: 利用反射机制生成一个实现代理接口的匿名类,在调用具体方法前调用InvokeHandler来处理。 cglib动态代理: 利用asm开源包,对代理对象类的class文件加载进来,通过修改其字节码生成子类来处理。 JDK动态代理和CGLIB字节码生成的区别? JDK动态代理只能对实现了接口的类生成代理,而不能针对类 CGLIB是针对类实现代理,主要是对指定的类生成一...

日拱一卒 5294

JAVA设计模式之动态代理

本文转载自:https://www.cnblogs.com/lfdingye/p/7717063.html 作者:lfdingye 转载请注明该声明。动态代理模式主要由四个元素共同构成:   1. 接口,接口中的方法是要真正去实现的   2. 被代理类,实现上述接口,这是真正去执行接口中方法的类   3. 代理类,实现InvocationHandler,帮助被代理类去实现方法   4. ...

xfxf996的博客 91

javabean反射改字段内容_BAT程序员编写:深入理解 Java 反射和动态代理源码分析...

什么是反射反射(Reflection)是 Java 程序开发语言的特征之一,它允许运行中的 Java 程序获取自身的信息,并且可以操作类或对象的内部属性。通过反射机制,可以在运行时访问 Java 对象的属性,方法,构造方法等。反射的应用场景反射的主要应用场景有:开发通用框架 - 反射最重要的用途就是开发各种通用框架。很多框架(比如 Spring)都是配置化的(比如通过 XML 文件配置 JavaB...

weixin_42371574的博客 108

从零构建Java RPC框架Jaws:深入理解Netty、动态代理与分布式服务治理

RPC(远程过程调用)是分布式系统通信的基石,其核心原理在于通过网络让一台计算机上的程序调用另一台计算机上的子程序,如同本地调用一样。这一技术通过封装底层的网络通信、序列化和服务寻址等复杂细节,为构建高性能、可扩展的微服务架构提供了关键支撑。在Java技术栈中,Netty作为高性能的网络通信框架,结合动态代理技术,是实现透明化远程调用的工程实践基础。理解其线程模型、编解码器及连接管理机制,对于开发高并发中间件至关重要。本文以教学实践项目Jaws为例,系统拆解了如何整合Netty NIO模型与一致性哈希负载均

weixin_32932149的博客 219

Java笔记之代理

1、静态代理 package staticProxy; public interface Person { public void say(); } package staticProxy; public class Chinese implements Person { public void say() { System.out.println("I...

162

8、Java 代理模式从入门到实战

代理类型核心特点目标类要求依赖执行效率适用场景静态代理手动编写代理类,增强逻辑固定需实现接口(或继承类)无(原生Java)最高(无反射/字节码开销)简单场景、目标类少JDK动态代理运行时动态生成代理类,增强逻辑可复用必须实现接口无(原生Java)中等(反射开销)目标类有接口(主流场景)CGLIB动态代理运行时动态生成子类,增强逻辑可复用无接口要求,不能是final类CGLIB框架(Spring已集成)较高(字节码增强,无反射开销)目标类无接口、遗留系统。

Rsun2018的博客 288

结构型之代理模式

序言   代理模式可以实现对被代理对象的间接控制,可以对被代理对象的方法进行增强,她不重写原有的方法。 代理模式基本分为3类: jdk静态代理: 1个代理类只能代理1个类,局限性较大。 jdk动态代理: 1个代理类能代理多个类,要求被代理类必须要有接口,利用了反射,效率比较低。 cglib动态代理:1个代理类能代理多个类,被代理类不需要有接口,效率较高,不能代理final的类和方法 1. ...

weixin_30516243的博客 63

Java 代理模式全链路解析与大厂面试避坑指南

代理模式给某一个对象提供一个代理对象,并由代理对象控制对原对象的引用。真实对象 (Real Subject):最终要执行业务逻辑的对象。代理对象 (Proxy):持有了真实对象的引用,负责预处理消息、过滤消息、把消息转发给真实对象,以及事后处理消息。代理模式是 Java 框架“灵活性”的源泉。掌握了代理,你就能读懂 Spring 的事务回滚逻辑,就能理解 MyBatis 是如何把一个接口变成 SQL 执行引擎的。这篇文章梳理了代理模式的所有命门。

u011377152的博客 332
上一篇: 注解+反射练习
下一篇: Java:线程与进程入门
pillow_mycode
博客等级 码龄3年 34粉丝 9原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值