动态代理在Java中有着广泛的应用,如Spring AOP,Hibernate数据查询、测试框架的后端mock、RPC,Java注解对象获取等。动态代理的代理关系是在运行时期确定的。接下来主要阐述两种动态代理的区别。
JDK和CGLib动态代理分析
自Java 1.3以后,Java提供了动态代理技术,允许开发者在运行期创建接口的代理实例,后来这项技术被用到了Spring的很多地方。JDK动态代理主要涉及java.lang.reflect包下边的两个类:Proxy和InvocationHandler。其中,InvocationHandler是一个接口,可以通过实现该接口定义横切逻辑(如:我们在方法执行前后打印的日志,本文只是为了演示,实际的应用一般不会只是简单的打印日志的),并通过反射机制调用目标类的代码,动态地将横切逻辑和业务逻辑编织在一起。
JDK动态代理的话,他有一个限制,就是它只能为接口创建代理实例,而对于没有通过接口定义业务方法的类,如何创建动态代理实例哪?答案就是CGLib。
CGLIB(Code Generation Library)是一个基于ASM的字节码生成库,它允许我们在运行时对字节码进行修改和动态生成。CGLIB通过继承方式实现代理,在子类中采用方法拦截的技术拦截所有父类方法的调用并顺势织入横切逻辑。
JDK和CGLib动态代理区别
1、JDK动态代理具体实现原理:
通过实现InvocationHandler接口创建自己的调用处理器;
通过为Proxy类指定ClassLoader对象和一组interface来创建动态代理;
通过反射机制获取动态代理类的构造函数,其唯一参数类型就是调用处理器接口类型;
通过构造函数创建动态代理类实例,构造时调用处理器对象作为参数参入;
JDK动态代理是面向接口的代理模式,如果被代理目标没有接口那么Spring也无能为力,Spring通过Java的反射机制生产被代理接口的新的匿名实现类,重写了其中AOP的增强方法。
2、CGLib动态代理:
利用ASM开源包,对代理对象类的class文件加载进来,通过修改其字节码生成子类来处理。
3、两者对比:
JDK动态代理是面向接口的。
CGLib动态代理是通过字节码底层继承要代理类来实现,因此如果被代理类被final关键字所修饰,会失败。
4、使用注意:
如果要被代理的对象是个实现类,那么Spring会使用JDK动态代理来完成操作(Spirng默认采用JDK动态代理实现机制);
如果要被代理的对象不是个实现类那么,Spring会强制使用CGLib来实现动态代理。
JDK和CGLib动态代理性能对比
关于两者之间的性能的话,网上有人对于不通版本的jdk进行测试,经过多次试验,测试结果大致是这样的,在1.6和1.7的时候,JDK动态代理的速度要比CGLib动态代理的速度要慢,但是并没有教科书上的10倍差距,在JDK1.8的时候,JDK动态代理的速度已经比CGLib动态代理的速度快很多了,但是JDK动态代理和CGLIB动态代理的适用场景还是不一样的哈!
参考来源:https://zhuanlan.zhihu.com/p/106336169
网友回复
腾讯混元模型广场里都是混元模型的垂直小模型,如何api调用?
为啥所有的照片分辨率提升工具都会修改照片上的图案细节?
js如何在浏览器中将webm视频的声音分离为单独音频?
微信小程序如何播放第三方域名url的mp4视频?
ai多模态大模型能实时识别视频中的手语为文字吗?
如何远程调试别人的chrome浏览器获取调试信息?
为啥js打开新网页window.open设置窗口宽高无效?
浏览器中js的navigator.mediaDevices.getDisplayMedia屏幕录像无法录制SpeechSynthesisUtterance产生的说话声音?
js中mediaRecorder如何录制window.speechSynthesis声音音频并下载?
python如何直接获取抖音短视频的音频文件url?