CGLIB动态代理探索(ASM,Spring)

简介: 文章概览一. 基本介绍二. 源码探索三. FastClass四. CGlib比JDK快?五. CGLIB和Jdk动态代理的区别六. ASM七. SpringAOP

网络异常,图片无法展示
|





文章概览


一.  基本介绍


二.  源码探索


三.  FastClass


四.  CGlib比JDK快?


五.  CGLIB和Jdk动态代理的区别


六.  ASM


七.  SpringAOP


基本介绍


CGLIB(Code Generation Library),是一个强大的,高性能,高质量的Code生成类库,它可以在运行期扩展Java类与实现Java接口。


1.先在 pom 文件中引入这个包


<dependency>
    <groupId>cglib</groupId>
    <artifactId>cglib</artifactId>
    <version>3.2.7</version>
</dependency>
复制代码


2.实现 MethodInterceptor 接口


代码如下, 这里实现 MethodInterceptor 接口,并重写 intercept 方法,感觉这一步和 JDK动态代理 差不多 😄


网络异常,图片无法展示
|


3.增强调用


最后在客户端中进行增强调用即可~🐷


// Cglib 动态代理
// 代理类class文件存入本地磁盘方便我们反编译查看源码
System.setProperty(DebuggingClassWriter.DEBUG_LOCATION_PROPERTY, "./code");
// 通过CGLIB动态代理获取代理对象的过程
Enhancer enhancer = new Enhancer();
// 设置enhancer对象的父类
enhancer.setSuperclass(UserService.class);
// 设置enhancer的回调对象
enhancer.setCallback(new MyInterceptor());
// 创建代理对象
UserService userService = (UserService)enhancer.create();
// 通过代理对象调用目标方法
userService.say();
userService.finalMethod();
UserService.staicMethod();
复制代码


4.结果


结果如下,可以发现只有 say 方法被增强了,被 final 或者 static 修饰的无法被代理


网络异常,图片无法展示
|


源码探索


在上面的代码中有配置这个字节码的生成👆 ,可以发现目录中多了个 code 目录,而且居然生成了三份字节码文件


网络异常,图片无法展示
|


查看第二个字节码文件,如下图👇


可以发现它 继承 了我们的被代理类 UserService ,其他两个文件则 继承FastClass


网络异常,图片无法展示
|


至于其他两个文件怎么调用呢,我也不了解……


网络异常,图片无法展示
|


哈哈哈 不过咱们 debug 一下就可以猜出来啦~


say 方法处打个断点🐷,然后可以看到这里在调用 invoke 方法时出现了这个 14


网络异常,图片无法展示
|


在这三个文件中,搜索后发现 只有第一个文件有这个 14 ,分析源码后可以发现这个 var10000 是表示第二个字节码文件


网络异常,图片无法展示
|


在第二个字节码文件中,CGLIB$say$0 方法如下图红框中所示~ 。


网络异常,图片无法展示
|


点击进去会去到它继承的 UserService 类的 say 方法~


那么至于第三个字节码文件的作用嘛…… 就真的不知道了 哈哈😄


网络异常,图片无法展示
|


FastClass


1.那什么是 FastClass 机制呢?


FastClass机制就是对一个类的方法建立索引,通过索引来直接调用相应的方法

2.在方法中调用另一个方法,会被增强几次呢?


突然奇想,哈哈😄


那么修改下方法,再重新运行下👇


网络异常,图片无法展示
|


可以看到这里出现了 两次


网络异常,图片无法展示
|


3.StackOverflowError


在拦截器 MethodInterceptorintercept 方法中,我们除了使用方法代理类MethodProxyinvokeSuper 外,它还有一个 invoke 方法可以给我们使用。


但是,在我使用这个 invoke 方法时,却出现了 栈溢出 的情况! 如图🐖


网络异常,图片无法展示
|


这什么情况呀🐖


网络异常,图片无法展示
|


于是我仔细阅读了这个方法说明,发现这两个方法使用的描述不一样~


网络异常,图片无法展示
|


抱着试试看的心态,将 参数换为 原始对象 ,结果成功了! ,而且看结果,可以发现只代理了一次😄


网络异常,图片无法展示
|


4.第三个字节码文件


在出现了这个栈溢出后,我也尝试着 debug 了一下,结果居然有了意外的收获 哈哈~

可以看到这里是调用 f1 的,对应着我们第三个字节码文件! 而且调用方式也是一样,通过这个方法的下标~


网络异常,图片无法展示
|


也是找到了如下的方法!


网络异常,图片无法展示
|


那么到此,这三个字节码文件的大致作用我们就了解啦~


哈哈 没想到一下这经历了这么多😄(从不知道 ——> 真不知道 ——> 大致知道 )

当然,这个框架的精髓还在最底层的 ASM ,这是一个小而快的字节码处理框架,用来转换字节码并生成新的类,是一个非常有意思的技术! (不过这我真不会了…… 哈哈哈 为啥总有种欠打的感觉~ 可能蕉太狼的表情包有毒 哈哈)


不过一些小技术要点,应用场景还是稍微了解过滴~(后面再介绍下)


网络异常,图片无法展示
|


5.方法代理 MethodProxy


仔细观赏上面后,我们可以发现这个 MethodProxyCglib 中非常重要的一环!

比如:


  1. MethodProxy 中通过 FastClassInfo 保存 FastClass 和调用方法的 index 下标


  1. 只代理 非final 或者 非static 方法


  1. 如果需要对所有的方法进行增强调用,可以使用 invokeSuper (第一个参数为增强的对象)。


  1. 如果只想对调用的方法进行增强,不增强该方法内部使用到的同类中的其他方法,可以使用 invoke 方法 (第一个参数为原始对象


小图小结


老规矩,来画个小图小结下👇


网络异常,图片无法展示
|


注意,拦截方法时,会根据这个增强的对象进行选择 f1 ,f2 ; 他们是两个不同的 FassClass 文件(f2名字最长~)


  1. 如果传如的是代理对象,则会选择 f2


  1. 如果是原始对象,则会选择 f1


  1. 接着根据方法的下标 index 去文件中查找对应的方法,并进行调用~


CGlib比JDK快?


使用 CGLiB 实现动态代理,CGLib 底层采用 ASM 字节码生成框架,使用字节码技术生成代理类, 在 jdk6 之前比使用 Java 反射效率要高。唯一需要注意的是,CGLib 不能对声明为 final 的方法进行代理, 因为 CGLib 原理是动态生成被代理类的子类。

jdk6jdk7jdk8 逐步对JDK动态代理优化之后,在调用次数较少的情况下,JDK代理效率 高于 CGLIB代理效率。只有当进行大量调用的时候,jdk6jdk7CGLIB 代理效率低一点,但是到jdk8的时候,jdk代理效率高于CGLIB代理,总之,每一次 jdk版本升级JDK代理效率 都得到提升,而 CGLIB代理效率 确有点跟不上步伐。

—— blog.csdn.net/m0_57711043…


CGLIB和Jdk动态代理的区别


关于 JDK动态代理的可以查看上文👉 Java代理模式和字节码的探索


  1. Jdk动态代理 只能对实现了接口的类进行代理 ,而 CGLIB 只能代理非final 类,因为它要去生成代理类的子类(没有 Jdk动态代理 的局限性)


  1. Jdk动态代理 生成的字节码文件中,代理类都继承了 Proxy 类,并实现了接口,而且生成字节码的效率CGLIB 高(cglib 一式三份 ,jdk只有一份)


  1. Jdk动态代理 中有个显眼的变量 hdebug 时多留意下就可以了~


  1. CGLIB 底层使用 ASM 框架来操作字节码文件,同时利用 FassClass 机制,实现对方法的快速索引并直接调用,不用经过反射,而 Jdk动态代理 则采用反射API进行操作


ASM


介绍


ASM 是一个通用的 Java 字节码操作和分析框架


结合上面的 cglib 有这么一张图(来自网络)


网络异常,图片无法展示
|


ASM 的用途:


  1. AOP


  1. 结合 javaagent 可以实现 热部署,以及日志追踪(类似 SkyWalking )


  1. arthas 的运行也是基于这个 javaagentASM 的,同时还使用到 JVMTI(JVM Tool Interface)


真就知道这点皮毛 哈哈哈


网络异常,图片无法展示
|


Spring AOP


嘿嘿,赶紧来看最后一点吧~ 在 Spring 中的使用


Spring 中,有下面这么两个代理类: JdkDynamicAopProxyCglibAopProxy


网络异常,图片无法展示
|


JdkDynamicAopProxy


源码如下👇


网络异常,图片无法展示
|


CglibAopProxy


这里删去了很多代码,可以看到高亮的部分使用到了我们上面提到的 enhancer


网络异常,图片无法展示
|


有没有小伙伴好奇在 Spring 中 , 实现了MethodInterceptor 的动态代理类中,是使用 methodProxyinvoke 还是 invokeSuper 方法呢?


网络异常,图片无法展示
|


答案就在这里~ 如图,这里前两个是用到了这个 invoke ,后面的几个是都没有用到 invokeinvokeSuper


目前


网络异常,图片无法展示
|


不过耐心点点看还是发现有用到这个 invokeSuper 的 , 比如


网络异常,图片无法展示
|

网络异常,图片无法展示
|


SpringAOP 小结


Spring 中:


  1. 对象实现接口,使用 JDK动态代理


  1. 对象没有实现接口,使用 Cglib动态代理


  1. 可以强制使用CGlib ,配置 @EnableAspectJAutoProxy(proxyTargetClass = true) 或者 spring.aop.proxy-target-class=true


总结


这次的内容比较多,就弄成了个思维导图啦,最主要的是 cglib 特点, FassClass机制 以及 Cglib和JDK动态代理的对比 ,还有 SpringAOP 这四个,扩展的有这个 ASM😄


小伙伴们如果需要这个思维导图可以直接在公众号后台回复 "代理模式2" 获取😝


网络异常,图片无法展示
|



目录
相关文章
|
6月前
|
监控 Java 开发者
Spring AOP动态代理
Spring AOP动态代理
100 1
|
6月前
|
运维 Java 程序员
Spring5深入浅出篇:Spring动态代理详解
# Spring动态代理详解 本文探讨了Spring中的MethodBeforeAdvice和MethodInterceptor在动态代理中的应用和差异。MethodBeforeAdvice在方法执行前执行额外功能,而MethodInterceptor则可在方法执行前后或抛出异常时运行额外逻辑。MethodInterceptor还能影响原始方法的返回值。
|
3月前
|
Java
Spring5入门到实战------9、AOP基本概念、底层原理、JDK动态代理实现
这篇文章是Spring5框架的实战教程,深入讲解了AOP的基本概念、如何利用动态代理实现AOP,特别是通过JDK动态代理机制在不修改源代码的情况下为业务逻辑添加新功能,降低代码耦合度,并通过具体代码示例演示了JDK动态代理的实现过程。
Spring5入门到实战------9、AOP基本概念、底层原理、JDK动态代理实现
|
29天前
|
Java 数据安全/隐私保护 Spring
Spring进阶:初识动态代理
本文介绍了Spring框架中AOP切面编程的基础——动态代理。通过定义Vehicle接口及其实现类Car和Ship,展示了如何使用动态代理在不修改原代码的基础上增强功能。文章详细解释了动态代理的工作原理,包括通过`Proxy.newProxyInstance()`方法创建代理对象,以及`InvocationHandler`接口中的`invoke()`方法如何处理代理对象的方法调用。最后,通过一个测试类`TestVehicle`演示了动态代理的具体应用。
|
2月前
|
设计模式 Java 测试技术
spring复习04,静态代理动态代理,AOP
这篇文章讲解了Java代理模式的相关知识,包括静态代理和动态代理(JDK动态代理和CGLIB),以及AOP(面向切面编程)的概念和在Spring框架中的应用。文章还提供了详细的示例代码,演示了如何使用Spring AOP进行方法增强和代理对象的创建。
spring复习04,静态代理动态代理,AOP
|
5月前
|
XML Java 数据格式
Spring5系列学习文章分享---第三篇(AOP概念+原理+动态代理+术语+Aspect+操作案例(注解与配置方式))
Spring5系列学习文章分享---第三篇(AOP概念+原理+动态代理+术语+Aspect+操作案例(注解与配置方式))
51 0
|
5月前
|
Java Spring
深入解析Spring源码,揭示JDK动态代理的工作原理。
深入解析Spring源码,揭示JDK动态代理的工作原理。
59 0
|
6月前
|
监控 Java 数据库连接
Spring高手之路17——动态代理的艺术与实践
本文深入分析了JDK和CGLIB两种动态代理技术在Spring框架中的应用。讨论了动态代理的基础概念,通过实例展示了如何实现和应用这两种方法,并比较了它们的性能差异及适用场景。进一步,探讨了在动态代理中实现熔断限流和日志监控的策略,以及如何利用动态代理优化Spring应用的设计和功能。
123 6
Spring高手之路17——动态代理的艺术与实践
|
6月前
|
Java 数据库 Spring
切面编程的艺术:Spring动态代理解析与实战
切面编程的艺术:Spring动态代理解析与实战
62 0
切面编程的艺术:Spring动态代理解析与实战
|
6月前
|
设计模式 运维 Java
Spring5深入浅出篇:Spring中静态代理与动态代理
Spring框架中的代理模式分为静态代理和动态代理。在JavaEE分层开发中,Service层最为重要,包含核心业务逻辑和额外功能。静态代理通过手动创建代理类来增加原始类的额外功能,但当代理类数量多时管理不便且不易于维护。动态代理则解决了这一问题,通过Spring的AOP(面向切面编程)实现,无需手动创建代理类,只需定义切点和增强(额外功能),在运行时动态生成代理对象,提高了代码的灵活性和可维护性。动态代理主要利用了JVM的字节码技术,在运行过程中创建代理类,执行完毕后随着虚拟机的结束而销毁,不会产生持久化的代理类。