首页
学习
活动
专区
工具
TVP
发布
精选内容/技术社群/优惠产品,尽在小程序
立即前往

动态代理——CGLIB动态代理原理&示例解析

觉得可以的话点个关注,转个发呗,陆续奉上干货~~~~

前文我们讲解了JDK动态代理的原理(动态代理——JDK动态代理原理),今天我们来看看CGLIB动态代理是如何实现的,最后我们总结下JDK动态代理和CGLIB动态代理的区别~~

先看下测试的源码:

CGLIB动态代理测试代码

输出:

我们看下CGLIB生成的代理类(精简之后):

生成的代理类(子类)

通过注释我们可以观察到代理类以及代理对象的实现方式:

首先CGLIB使用ASM工具根据父类HelloServiceImpl.class及我们定义的方法拦截器MethodInterceptor生成代理CglibTest$HelloServiceImpl$$EnhancerByCGLIB$$69dcec54的字节码,然后将该字节码加载到虚拟机并根据静态代码块使用INIT方法初始化类中的类变量parentSayHelloMethod、sayHelloMethodProxy(及其他信息,截图中已省略其他信息,防干扰)

实例化代理类CglibTest$HelloServiceImpl$$EnhancerByCGLIB$$69dcec54的对象,记为代理对象A,并伴随着代理类中的成员属性methodInterceptor初始化为我们定义的MethodInterceptor对象,因为我们的代理类继承了HelloServiceImpl,因此可以强转(HelloServiceImpl)A

调用代理对象的sayHello方法:(HelloServiceImpl)A.sayHello(...)

结合上图,我们看到调用sayHello实际上调用了我们定义的MethodInterceptor的methodInterceptor方法

methodInterceptor方法

接下来我们关注红框中的方法:

methodProxy这个对象是在生成的代理类的INIT方法中进行初始化的(上去看下图):

我们看下create方法:

创建methodProxy对象

接下来看invokeSuper方法:

invokeSuper方法

我们来看下init方法,为了说明init方法的意思,写了两个类(真实的这两个类也是CGLIB动态生成的,内部为每个方法描述生成了唯一的索引并使用switch表达式进行分支控制,本例为了简单说明是使用if语句根据方法名称进行判断,理解意思即可)

完成上面的初始化后我们进入到这个方法的分析:

f2指向Proxy$$FastClass实例(上面的注释),调用的就是proxy.cglibSayHello((String)args[0])这个方法,我们再回到最开始生成的代理类中,查看cglibSayHello方法,调用的是父类的sayHello方法:

这样就形成了一个闭环~~~~

因此CGLIB在这一部分的优化就是用了判断的形式直接调用的对象的方法,付出的代价是多加载了几个类到虚拟机中,是一种空间换时间的一种思想;而JDK的方式是使用方法对象进行反射调用,节省了空间但降低了效率

总结JDK动态代理和CGLIB动态代理:(两种实现方式大体思路基本相同)

JDK动态代理:

需要目标类实现接口

生成的代理类是与目标类平级,实现了共同的接口

使用反射的方式进行最终方法的调用,性能较低

CGLIB动态代理:

不要求目标类实现接口

生成的代理类是目标类的子类

final方法不会出现在代理类中

使用空间换时间的思想对最终的方法调用进行了优化,提升了运行时性能

Over~~

  • 发表于:
  • 原文链接https://kuaibao.qq.com/s/20210119A05D4K00?refer=cp_1026
  • 腾讯「腾讯云开发者社区」是腾讯内容开放平台帐号(企鹅号)传播渠道之一,根据《腾讯内容开放平台服务协议》转载发布内容。
  • 如有侵权,请联系 cloudcommunity@tencent.com 删除。

扫码

添加站长 进交流群

领取专属 10元无门槛券

私享最新 技术干货

扫码加入开发者社群
领券