当前位置: 首页 > news >正文

java 代理模式实现

代理

代理模式

代理模式是一种结构型设计模式,概念为通过一个代理对象来控制对原始对象的访问,代理对象通常表现出的行为与原始对象一致(实现同一接口)以便于可以在使用原始对象的地方代替原始对象。使用代理模式一般用来保护以及增强原始对象。

静态代理与动态代理

编译期间就确定好了代理类与被代理类为静态代理,其中代理类与被代理类会实现同一个接口,代理类持有被代理类,代理类可以调用被代理类方法并添加逻辑。

动态代理的代理类是运行期间动态生成的,其他地方与静态代理相同。很显然在被代理类很多时使用动态代理可以节省代码且方便修改逻辑。

静态代理一般来说效率稍高,但是代码冗余大,不便于修改。

动态代理一般使用 jdk 动态代理和 cglib 动态代理。

jdk 动态代理

jdk 动态代理是基于实现接口的方式,代理类是动态生成的和被代理类实现同一接口且持有被代理类实例的类。

很显然 jdk 动态代理是代理不了接口中没有的方法的。

jdk 动态代理基于反射,代理类与被代理类是委托关系,使用 Proxy 生成字节码文件。

涉及到以下几个类和接口

InvocationHandler 接口

动态代理类需要实现这个接口且持有被代理类实例,通过代理对象调用一个方法时,这个方法的调用会被转发由这个接口的 invoke 方法来进行调用

// InvocationHandler 唯一的接口
Object invoke(Object proxy, Method method, Object[] args)throws Throwable 

参数说明:

  • proxy - 被代理类实例
  • method - 被代理类的某个方法的 Method 对象
  • args - 调用被代理类某个方法时需要的参数列表
Proxy 类

Proxy 这个类的作用就是用来动态创建一个代理对象的类,它提供了许多的方法,用的最多的就是 newProxyInstance 方法:

//得到一个动态的代理对象
public static Object newProxyInstance(ClassLoader loader, Class<?>[] interfaces,  InvocationHandler h)  throws IllegalArgumentException

参数说明:

  • loader - 一个 ClassLoader 对象,定义了由哪个 ClassLoader 对象来对生成的代理对象进行加载
  • interfaces - 一个接口对象的数组,表示代理对象需要实现的接口
  • h - 一个 InvocationHandler 对象,表示代理对象调用方法时需要关联的 InvocationHandler 对象
动态生成的类

只会生成一个类,这是其反编译后的代码示例

//继承了java.lang.reflect.Proxy,实现了被代理类的接口
public final class $Proxy0 extends Proxy implements Subject {private static Method m1;private static Method m2;private static Method m3;private static Method m0;public $Proxy0(InvocationHandler var1) {//使用父类的构造方法super(var1);}...public final void deal() {try {//调用InvocationHandler的invoke方法super.h.invoke(this, m3, (Object[])null);} catch (RuntimeException | Error var2) {throw var2;} catch (Throwable var3) {throw new UndeclaredThrowableException(var3);}}...static {try {//Object的equals方法m1 = Class.forName("java.lang.Object").getMethod("equals", Class.forName("java.lang.Object"));//Object的toString方法m2 = Class.forName("java.lang.Object").getMethod("toString");//被代理类的接口中的方法,如果接口中有多个方法会往后延m3 = Class.forName("动态代理.jdk动态代理.Subject").getMethod("deal");//Object的hashCode方法m0 = Class.forName("java.lang.Object").getMethod("hashCode");} catch (NoSuchMethodException var2) {throw new NoSuchMethodError(var2.getMessage());} catch (ClassNotFoundException var3) {throw new NoClassDefFoundError(var3.getMessage());}}
}

其调用关系为

调用方 -> 动态生成的代理类的对应方法 -> 拦截器的 invoke 方法 -> 被代理类的对应方法

cglib 动态代理

cglib 动态代理是基于继承的方式,代理类是动态生成的继承了被代理类的类,使用重写方法的方式实现增强。

由于 cglib 动态代理是基于继承的,因此代理不了私有方法、final 方法、静态方法和构造方法,以及被声明为 final 的类。

cglib 动态代理基于FastClass方法索引,第一次调用需要生成 Class 对象较慢,代理类与被代理类是继承关系,使用ASM框架生成字节码文件。

MethodInterceptor

拦截器需要实现的接口,通过代理对象调用一个方法时,这个方法的调用会被转发由这个接口的 intercept 方法来进行调用

public Object intercept(Object o, Method method, Object[] args, MethodProxy methodProxy) throws Throwable

参数说明:

  • o - 代理类
  • method - 被代理的方法
  • args - 调用时的参数
  • methodProxy - 方法的代理类
FastClass

索引类,其中有两个主要的方法

  • getIndex - 获取目标的编号;索引类记录了目标方法与编号之间的对应关系,传递方法签名信息并返回对应编号
  • invoke - 根据方法编号,调用目标方法;三个参数分别代表
    • index - 方法编号
    • target - 目标对象
    • args - 方法执行所需参数
//代理类的FastClass
public class RealSubject$$FastClassByCGLIB$$b86fb30b extends FastClass {public RealSubject$$FastClassByCGLIB$$b86fb30b(Class var1) {super(var1);}//根据方法的签名获取对应的索引public int getIndex(Signature var1) {String var10000 = var1.toString();switch(var10000.hashCode()) {case 1540437897:if (var10000.equals("deal()V")) {return 0;}break;...}return -1;}...//根据方法索引调用被索引类的对应方法public Object invoke(int var1, Object var2, Object[] var3) throws InvocationTargetException {RealSubject var10000 = (RealSubject)var2;int var10001 = var1;try {switch(var10001) {case 0:var10000.deal();return null;...}} catch (Throwable var4) {throw new InvocationTargetException(var4);}throw new IllegalArgumentException("Cannot find matching method/constructor");}...
}
MethodProxy

在代理类初始化时被创建

public class RealSubject$$EnhancerByCGLIB$$679604bd extends RealSubject implements Factory {...private static Method CGLIB$deal$0$Method;private static MethodProxy CGLIB$deal$0$Proxy;...static void CGLIB$STATICHOOK1() throws ClassNotFoundException {...CGLIB$deal$0$Method = ReflectUtils.findMethods(new String[]{"deal", "()V"}, (var1 = Class.forName("动态代理.cglib动态代理.RealSubject")).getDeclaredMethods())[0];//关联了代理的方法与被代理的方法CGLIB$deal$0$Proxy = MethodProxy.create(var1, var0, "()V", "deal", "CGLIB$deal$0");}static {try {CGLIB$STATICHOOK1();} catch (ClassNotFoundException e) {e.printStackTrace();}}
}

在 invoke 或者 invokeSuper 方法调用时被初始化

public class MethodProxy {public Object invoke(Object obj, Object[] args) throws Throwable {try {//初始化this.init();MethodProxy.FastClassInfo fci = this.fastClassInfo;return fci.f1.invoke(fci.i1, obj, args);} catch (InvocationTargetException var4) {throw var4.getTargetException();} catch (IllegalArgumentException var5) {if (this.fastClassInfo.i1 < 0) {throw new IllegalArgumentException("Protected method: " + this.sig1);} else {throw var5;}}}public Object invokeSuper(Object obj, Object[] args) throws Throwable {try {//初始化this.init();MethodProxy.FastClassInfo fci = this.fastClassInfo;return fci.f2.invoke(fci.i2, obj, args);} catch (InvocationTargetException var4) {throw var4.getTargetException();}}private void init() {//如果没有初始化的话if (this.fastClassInfo == null) {synchronized(this.initLock) {if (this.fastClassInfo == null) {MethodProxy.CreateInfo ci = this.createInfo;MethodProxy.FastClassInfo fci = new MethodProxy.FastClassInfo();//获取代理类和被代理类的索引类,其中f1是被代理类的索引类,f2是代理类的索引类fci.f1 = helper(ci, ci.c1);fci.f2 = helper(ci, ci.c2);//类似的,i1是被代理方法的索引值,i2是代理类的索引值fci.i1 = fci.f1.getIndex(this.sig1);fci.i2 = fci.f2.getIndex(this.sig2);this.fastClassInfo = fci;this.createInfo = null;}}}}
}
动态生成的类

会生成三个类,分别是代理类、代理类的索引类、被代理类的索引类

//动态生成的代理类
public class RealSubject$$EnhancerByCGLIB$$679604bd extends RealSubject implements Factory {...//直接调用被代理方法的方法final void CGLIB$deal$0() {super.deal();} //重写的被代理类的方法public final void deal() {MethodInterceptor var10000 = this.CGLIB$CALLBACK_0;if (var10000 == null) {CGLIB$BIND_CALLBACKS(this);var10000 = this.CGLIB$CALLBACK_0;}if (var10000 != null) {try {//调用拦截器的intercept方法var10000.intercept(this, CGLIB$deal$0$Method, CGLIB$emptyArgs, CGLIB$deal$0$Proxy);} catch (Throwable e) {e.printStackTrace();}} else {super.deal();}}...
}//代理类的FastClass
public class RealSubject$$EnhancerByCGLIB$$679604bd$$FastClassByCGLIB$$d3b917bf extends FastClass {...
}//代理类的FastClass
public class RealSubject$$FastClassByCGLIB$$b86fb30b extends FastClass {
}

其调用关系为

调用方 -> 动态生成的代理类的对应方法的重载 -> 自定义的拦截器的 intercept 方法 -> 代理类索引类的 invoke 方法 -> 动态生成的代理类的直接调用父类对应方法的实现 -> 被代理类

调用方代理类拦截器MethodProxy代理类索引类被代理类业务方法()1. intercept()2. 前置拦截3. invokeSuper()4. getIndex()5. 返回方法索引6. invoke()7. CGLIB$业务方法$?()8. 业务方法9. 返回10. 返回11. 返回12. 返回13. 后置拦截14. 返回15. 返回调用方代理类拦截器MethodProxy代理类索引类被代理类

文章转载自:

http://wAeAIvqO.bmfqg.cn
http://HJeHJZn2.bmfqg.cn
http://34xEK67M.bmfqg.cn
http://7uni7BKW.bmfqg.cn
http://f7srr4WL.bmfqg.cn
http://GmAWkIS2.bmfqg.cn
http://10HTyAzD.bmfqg.cn
http://ACNArufX.bmfqg.cn
http://r8Tl2RYF.bmfqg.cn
http://gWgnZjgH.bmfqg.cn
http://7y71qSdt.bmfqg.cn
http://yNuzR2II.bmfqg.cn
http://GXK7pLDN.bmfqg.cn
http://ImJ0xBSF.bmfqg.cn
http://G9nYNoXm.bmfqg.cn
http://1T9AQLaE.bmfqg.cn
http://qvLVI6td.bmfqg.cn
http://AtnsVG74.bmfqg.cn
http://VXxHpbg4.bmfqg.cn
http://3czD5dNk.bmfqg.cn
http://qG4sBEJj.bmfqg.cn
http://kDO4qxo2.bmfqg.cn
http://ZBCYPQOy.bmfqg.cn
http://1X9jXLC3.bmfqg.cn
http://aJZTLAJT.bmfqg.cn
http://7shR7skO.bmfqg.cn
http://WlwM85Z0.bmfqg.cn
http://fv2CNmRs.bmfqg.cn
http://VCDVpUxC.bmfqg.cn
http://M6r6gCVu.bmfqg.cn
http://www.dtcms.com/a/376601.html

相关文章:

  • 2025最新的软件测试面试八股文(800+道题)
  • 深入浅出LVS负载均衡群集:原理、分类与NAT模式实战部署
  • Nginx 配置 SSL/TLS 全指南:从安装到安全强化
  • 整体设计 之 绪 思维导图引擎 之 引 认知系统 之8 之 序 认知元架构 之4 统筹:范畴/分类/目录/条目 之2 (豆包助手 之6)
  • Android应用添加日历提醒功能
  • 【游戏开发】- 摄像机
  • B站 韩顺平 笔记 (Day 29)
  • Typescript入门-JSDoc注释及tsconfig讲解
  • Python快速入门专业版(十八):Python比较运算符深度解析:从基础判断到对象身份识别(附避坑指南)
  • 微服务网关实战:从三次灾难性故障到路由与权限的体系化防御
  • 从C++开始的编程生活(8)——内部类、匿名对象、对象拷贝时的编译器优化和内存管理
  • 【AI时代速通QT】第六节:Qt Creator从添加新窗口到项目构建运行配置
  • 【CVPR 2022】面向2020年代的卷积神经网络
  • 图神经网络介绍
  • FPGA入门到进阶:可编程逻辑器件的魅力
  • 【解决问题】Ubuntu18上无法运行arm-linux-gcc
  • 嵌入式学习day47-硬件-imx6ull-LED
  • 深入体验—Windows从零到一安装KingbaseES数据库
  • 力扣习题——电话号码的字母组合
  • Linux环境下爬虫程序的部署难题与系统性解决方案
  • 深入解析ThreadLocal:线程数据隔离利器
  • D01-【计算机二级】Python(1)基本操作第41题
  • API开发工具postman、国内xxapi和SmartApi的性能对比
  • Scikit-learn Python机器学习 - 分类算法 - 线性模型 逻辑回归
  • SciKit-Learn 全面分析 digits 手写数据集
  • 《sklearn机器学习——数据预处理》标准化或均值去除和方差缩放
  • 保序回归Isotonic Regression的sklearn实现案例
  • 《sklearn机器学习——数据预处理》离散化
  • 无人机桨叶转速技术要点与突破
  • GPFS存储服务如何使用及运维