CGLIB动态代理源码解析

220 阅读2分钟

环境

需要被代理的类:

在这里插入图片描述 在这里插入图片描述 运行结果: 在这里插入图片描述

代理对象如何增强源码(MethodInterceptor)

我们查看在运行时生成的代理类: 在这里插入图片描述 也就是这个类,我们先不看这些复杂的属性和方法,我们直接找到我们通过代理对象调用的test方法查看: 在这里插入图片描述

在这里插入图片描述

方法拦截器继承Callback类: 在这里插入图片描述 方法拦截器继承Callback类 可以看到步骤一是先对方法拦截器赋值,当代理对象的方法拦截器为null时通过步骤二的方法获取了拦截器,而步骤三则是调用了方法拦截器的intercept方法,这个intercept方法则就是我们开始的时候传入的方法拦截器时重写的方法: 在这里插入图片描述 因此当调用代理对象的方法时会直接走我们定义的拦截器对象重写的intercept方法。 我们再来看看步骤二是怎么进行拦截器设置的: 在这里插入图片描述 可以看到其是通过CGLIB$THREAD_CALLBACKS属性的get方法获取到callback再进行强转获得方法拦截器,查看该属性: 在这里插入图片描述 是一个ThreadLocal,那么到底是什么时候设置的ThreadLocal呢? 我们在这个类中找找看看有没有设置ThreadLocal的方法: 在这里插入图片描述 找到在这个方法中对ThreadLocal设置了callback,那么只能是在生成代理对象时调用该方法设置ThreadLocal的,我们来查看代理对象的创建,会让这个问题迎刃而解

代理对象的创建

在这里插入图片描述 在上图中,前面几个set方法通过其名字我们就知道是对enhancer对象的属性进行了填充,而create方法则是返回了代理对象,那么该方法中应该生成了代理类并且创建了代理对象,进入该方法底层: 在这里插入图片描述 查看第一个方法: 在这里插入图片描述 其应该是对我们设置的属性进行了检验。 而第二个方法可以看到传入了我们设置的父类等属性,则是将我们传入的参数封装成一个对象,然后通过create方法创建或者从根据对象从缓存中获取,进入create方法: 在这里插入图片描述 前面的我们先不管,直接找到return,其返回的是代理对象,那么步骤2一定是创建了代理对象,我们可以看到步骤2先验证了obj对象是不是类,如果是类则通过这个类创建了实例,那么步骤1应该就是生成代理类的过程,我们进入2中的方法最底层查看: 在这里插入图片描述 我们可以看到步骤1中的方法,传入了我们最开始自定义的方法拦截器,再根据其方法名称其实就可以直到其设置了ThreadLocal属性,而步骤2则是基于反射通过代理类创建了代理对象,进入步骤1的方法查看: 在这里插入图片描述 该方法传入了上文中我提到的代理类中设置ThreadLocal方法的方法名称,继续进入查看: 在这里插入图片描述 在该方法中,可以看出,就是基于反射通过代理类和方法名称调用代理类的方法设置ThreadLocal值。并且该操作是在生成代理类之后、创建代理对象之前。

而生成代理类的源码我们就不看了,大家有兴趣可以自己看看,主要是通过ASM库生成

CGLIB调用原方法(MethodProxy)

我们大部分已经学过JDK动态代理,知道其所有方法会到InvocationHandler的invoke方法中,在其中实现逻辑增强,实现逻辑增强后通过反射调用原对象的方法.

CGLIB则与JDK动态代理不同,其通过FastClass机制实现原对象的调用,我来带大家通过源码学习。 在这里插入图片描述 我们在生成的代理类中查看这个方法: 在这里插入图片描述 在这里插入图片描述

这四个参数分别是代理对象、原方法、方法参数和方法代理。 我们来查看这个MethodProxy: 在这里插入图片描述 这个create方法传入了被代理类、代理类、方法返回类型、被代理类方法名、代理类方法名。

在这里插入图片描述 步骤1:分别通过被代理类方法名、代理类方法名和返回类型设置方法签名sign1、sign2

sign1:被代理类的方法名:"test"以及void类型

sign1:代理类的方法名:"CGLIBtesttest0"以及void类型 查看步骤2方法: 在这里插入图片描述 设置c1、c2

c1:被代理类 c2:代理类 当调用MethodProxy的invoke方法时,进入查看: 在这里插入图片描述 查看init()方法: 在这里插入图片描述 步骤1根据c1、c2即代理类和被代理类创建了代理类和被代理类的FastClass代理,即我们运行时生成的其他两个类:

被代理类的FastClass代理: 在这里插入图片描述 代理类的FastClass代理: 在这里插入图片描述 我们大致查看这两个类,其中存在getIndex方法和invoke方法。

getIndex方法: 在这里插入图片描述 这个类会计算方法签名的哈希值,然后通过哈希值和方法名匹配返回一个整数。这个方法就是FastClass实现的关键。

我们再回步骤2查看,我们发现其就是通过方法签名s1和s2返回一个整数赋给c1、c2.

我们可以知道每一个通过MehodProxy调用的方法都会生成一个FastClassInfo对象,其属性包括: f1、f2、i1、i2.

f1:被代理类的FastClass代理

f2:代理类的FastClass代理

i1:被代理类的方法对应的索引下标(test方法)

i2:代理类方法对应的索引下标(CGLIBtesttest0方法)

回到invoke方法 在这里插入图片描述 那么我们就可以发现invoke调用逻辑就很简单了:到代理类的FastClass代理中获取方法对应的索引值返回,然后通过FastClass代理中invoke根据索引值执行相应的方法。 在这里插入图片描述 至于MethodProxy的invokeSuper方法大家可以尝试自己分析,步骤大差不差

CGLIB动态代理原理总结

增强逻辑

通过ASM字节码库生成被代理类的子类即代理类,需要自定义MethodInterceptor重写intercept方法,当生成代理对象,通过代理对象调用方法时,会中转到自定义的方法拦截器的intercept方法中,而方法拦截器的设置是在生成代理类后、通过反射创建代理对象前,将方法拦截器写入常量ThreadLocal中,代理对象获取方法拦截器时从ThreadLocal中获取。

增强后调用父类方法

当通过MethodProxy调用原方法时,会生成被代理类和代理类的FastClass代理,当调用invoke或invokeSuper时会分别从被代理类和代理类的FastClass代理中获取相应的方法索引值,然后通过索引值调用相应的方法