公司动态
Java动态代理如何实现
我的理解核心在不改变原来的代码的情况下如果要实现拓展新的功能通过代理实现再调用代理横向开发动态代理我的理解和静态代理作用是一样的但是静态代理我们代理的是一个角色动态代理可以代理一类角色一个动态代理一般代理某一类业务可以代理多个类代理的是接口首先必须先了解动态代理的优点1、代码复用性拉满、所有类共用不用重复编码2、易维护3、解耦彻底业务只管业务、日志、权限等通用逻辑全部集中管理4、适合批量全局增强全接口加监控、全方法加事务一行业务代码不用改。还有一个优点静态代理代码提前写好编译就有 class 文件 动态代理代码一行没写程序跑起来的时候 JVM 临时在内存现写 class用完就丢硬盘不留文件。从头到尾你没有新建任何代理类的 Java 文件。 程序跑起来之后运行阶段JDK/CGLIB 在内存里临时凭空拼出一份全新的 class 字节码直接交给 JVM 加载使用。 硬盘全程不会多出任何代理类的.java/.class 文件程序关闭内存里这份临时 class 直接消失。这就是运行时自动生成。静态代理手写代理类少量场景能用多了必难维护动态代理运行自动生成一套代码通用适配绝大多数开发。静态代理有的他都有静态怕多类、怕改方法动态怕没接口JDK、怕 finalCGLIB。从零完整复盘抛弃复杂术语一层一层捋顺1. 核心本质代理是什么不管静态、动态代理套路永远是 调用方不直接调用真实业务类先走代理。 代理负责日志、权限、事务、耗时统计 真实业务类只做本职功能杂活全部剥离。举例子你要调用用户新增方法 正常你 → UserServiceImpl真实类 代理模式你 → 代理类 → UserServiceImpl 好处不改真实类代码就能在方法前后加额外功能。2. 静态代理痛点引出为什么需要动态代理静态代理你手动新建代理.java 文件。 一个真实业务类必须手写一个专属代理类。 10 个业务类 手写 10 个代理类。 如果业务新增方法所有代理类必须手动新增对应方法维护极其麻烦。静态代理的代理类编译前就写好编译完硬盘永久存在代理.class 文件。3. 动态代理最关键没有手写代理类你全程只写 3 类代码 1业务接口 2真实实现类 3拦截处理器InvocationHandler 从头到尾你没有写任何代理的 Java 文件。 硬盘里不存在代理的.java、代理.class。重点运行时生成到底发生了什么代码执行到Proxy.newProxyInstance这一行程序跑起来的瞬间JDK 根据接口信息在内存里拼出来一份全新 class 字节码代理类JVM 加载这份内存里的 class创建出代理对象你调用代理的任意方法全部跳转进 invoke 方法invoke 写增强逻辑日志再调用真实对象的方法程序停止内存清空这份临时代理 class 直接消失硬盘不留任何痕迹。简单说代理类没有提前准备程序跑起来临时现做用完扔掉。4. 完整执行链路JDK 动态代理标准流程调用者 → 运行时生成的代理对象 → invoke 拦截方法前置增强→ 真实对象执行业务 → 后置增强返回结果5. 两个动态代理分类区别极简JDK 动态代理硬性要求真实类必须实现接口。 运行生成的代理类实现和目标一模一样的接口。 限制没有接口完全不能用。CGLIB 动态代理不需要接口。 运行时生成目标类的子类靠重写父类方法实现拦截。 限制final 类不能被继承无法代理final、私有方法拦截不到。6. 最大优势一句话记住只写一份拦截增强代码所有业务类全部复用。 以后新增业务类、新增方法不用修改代理相关任何代码。 这是动态代理碾压静态代理的核心。7. 配套生活化重讲静态代理每个快递员单独配专属驿站手写代理快递员越多驿站越多。 动态代理只有 1 个通用驿站handler没有专属驿站。程序运行时临时给当前快递员搭一个临时驿站内存生成代理用完拆掉。无论多少快递员共用一套驿站规则。8. 高频误区逐个澄清误区动态代理生成 java 源码 错。只会在内存生成二进制 class 字节码不会产生.java 文件。误区代理 class 会自动保存在电脑 错。默认只在内存关闭程序就没。只有配置特殊 JVM 参数才会把 class 保存到硬盘。误区invoke 执行目标方法用 proxy 错。必须 method.invoke (真实 target, 参数)填 proxy 会无限循环调用。9. 极简背诵版动态代理不用手写代理类运行时内存临时创建代理 class所有方法被统一拦截可以无侵入增加日志、事务、权限JDK 靠接口CGLIB 靠继承一份增强代码适配所有类易维护是 SpringAOP、事务底层原理。