jdk动态代理实例和cglib动态代理实例_CGLib 动态代理 原理解析

c51ef488e3d8a97181aee896c4d9c50b.png
  • JDK 动态代理实现与原理

首先来看一段CGLib代理的测试代码(MethodInterceptor的测试, 其他类型这里不做展开了). Util类的代码在后面给出的码云片段中

public 

下面的输出结果除了测试动态代理生效结果外, 还将动态代理生成的类名也输出出来了. 这些类名信息, 在后面的分析中会用到.

Current Pid is:54801
co/wangming/cglib/methodinterceptor/MethodInterceptorTest$A$$EnhancerByCGLIB$$b5ca7abc
proxy start : class net.sf.cglib.proxy.MethodProxy: class co.wangming.cglib.methodinterceptor.MethodInterceptorTest$A$$EnhancerByCGLIB$$b5ca7abc
*****************CreateInfo***********************
Proxy Class: class co.wangming.cglib.methodinterceptor.MethodInterceptorTest$A$$EnhancerByCGLIB$$b5ca7abc
CGLIB$printHi$0$Proxy CreateInfo : class net.sf.cglib.proxy.MethodProxy$CreateInfo
CGLIB$printHi$0$Proxy CreateInfo c1: class co.wangming.cglib.methodinterceptor.MethodInterceptorTest$A
CGLIB$printHi$0$Proxy CreateInfo c2: class co.wangming.cglib.methodinterceptor.MethodInterceptorTest$A$$EnhancerByCGLIB$$b5ca7abc
CGLIB$equals$1$Proxy CreateInfo : class net.sf.cglib.proxy.MethodProxy$CreateInfo
CGLIB$equals$1$Proxy CreateInfo c1: class java.lang.Object
CGLIB$equals$1$Proxy CreateInfo c2: class co.wangming.cglib.methodinterceptor.MethodInterceptorTest$A$$EnhancerByCGLIB$$b5ca7abc
CGLIB$toString$2$Proxy CreateInfo : class net.sf.cglib.proxy.MethodProxy$CreateInfo
CGLIB$toString$2$Proxy CreateInfo c1: class java.lang.Object
CGLIB$toString$2$Proxy CreateInfo c2: class co.wangming.cglib.methodinterceptor.MethodInterceptorTest$A$$EnhancerByCGLIB$$b5ca7abc
CGLIB$hashCode$3$Proxy CreateInfo : class net.sf.cglib.proxy.MethodProxy$CreateInfo
CGLIB$hashCode$3$Proxy CreateInfo c1: class java.lang.Object
CGLIB$hashCode$3$Proxy CreateInfo c2: class co.wangming.cglib.methodinterceptor.MethodInterceptorTest$A$$EnhancerByCGLIB$$b5ca7abc
CGLIB$clone$4$Proxy CreateInfo : class net.sf.cglib.proxy.MethodProxy$CreateInfo
CGLIB$clone$4$Proxy CreateInfo c1: class java.lang.Object
CGLIB$clone$4$Proxy CreateInfo c2: class co.wangming.cglib.methodinterceptor.MethodInterceptorTest$A$$EnhancerByCGLIB$$b5ca7abc
*****************CreateInfo***********************
hi
proxy over
hi
*****************FastClassInfo***********************
Proxy Class: class co.wangming.cglib.methodinterceptor.MethodInterceptorTest$A$$EnhancerByCGLIB$$b5ca7abc
CGLIB$printHi$0$Proxy FastClassInfo : class net.sf.cglib.proxy.MethodProxy$FastClassInfo
CGLIB$printHi$0$Proxy FastClass f1: class co.wangming.cglib.methodinterceptor.MethodInterceptorTest$A$$FastClassByCGLIB$$65f2d708
CGLIB$printHi$0$Proxy FastClass f2: class co.wangming.cglib.methodinterceptor.MethodInterceptorTest$A$$EnhancerByCGLIB$$b5ca7abc$$FastClassByCGLIB$$19e0f1ba
CGLIB$printHi$0$Proxy FastClass i1: 0
CGLIB$printHi$0$Proxy FastClass i2: 14
---->
---->
---->
---->
****************FastClassInfo************************

由于生成的代理类的代码过于长, 而知乎没有折叠功能, 所以我将这个代码片段放到了码云上面 . A的代理类的名称是: MethodInterceptorTest$A$$EnhancerByCGLIB$$b5ca7abc

cglib 动态代理 - 代码片段 - 码云 Gitee.com​gitee.com
be2c447c7c1839f7eef9803495aef9d9.png

从printHi()方法入手, 看看它的代理是怎么实现的.

// 在MethodInterceptorTest$A$$EnhancerByCGLIB$$b5ca7abc类内部, 有下面俩个和printHi方法相关的属性

上面简单分析了代理子类的实现, 但是这都不是重点, 真正的魔法在callback里面. demo里面callback是这么写的

enhancer.setCallback((MethodInterceptor) (obj, method, args1, proxy) -> {
			System.out.println("proxy start : " + proxy.getClass() + ": " + obj.getClass());
			Object res = proxy.invokeSuper(obj, args);
			System.out.println("proxy over");
			return res;
});

proxy参数的类型是MethodProxy类型, MethodProxy有俩个invoke方法:

  • invoke(Object obj, Object[] args): obj参数不能是MethodInterceptor#intercept()方法的第一个参数obj对象, 否则会造成栈溢出
  • invokeSuper(Object obj, Object[] args): obj参数必须是MethodInterceptor#intercept()方法的第一个参数obj对象

在使用MethodInterceptor的时候, 一定要注意上面这俩点, 下面我们就从invoke/invokeSuper方法入手, 分析一下.

由于这一块的源码过多, 我就不一一都贴出来了, 我画了俩张图帮大家理顺一下.

075909895d336b9e78d350e0f77cc09c.png

c8f84cae467320ff5e327305493079df.png

MethodProxy类里面有一个CreateInfo对象. CreateInfo内部有俩个Class对象, 分别是

  • c1: 目标类的Class对象
  • c2: 目标类的强化类的Class对象, 也就是CGLib生成的目标类的代理子类

CGLib会利用CreateInfo对象去构建出FastClassInfo这个对象. 构建过程就是通过CreateInfo的c1/c2去分别构建出FastClassInfo里面的FastClass类型的f1/f2.

也就是说, 真正的是构建了俩个FastClass对象出来. FastClass对象是通过FastClass内部类Generator进行构建的. 而内部类Generator是将构建过程交给了它的父类AbstractClassGenerator#generate()方法的.

AbstractClassGenerator#generate()又是通过其内部类GeneratorStrategy的对象执行了构建. 最终实现构建的是FastClass#Generator()的generateClass()方法, 该方法实例化了一个FastClassEmitter对象, FastClassEmitter对象内部就是通过ASM去构建Class对象的.

invoke/invokeSuper方法实现如下

public 

init()方法如下

private 

针对init()方法的过程可以参考一下下面的时序图

3b505415a0272a354e0687febecd6ce2.png

可以看出来, 整个CGLib的核心就在于这个FastClass

abstract 

FastClass是一个抽象类, CGLib在运行时通过FastClass内的Generator这个内部类将其子类动态生成出来, 然后再利用ClassLoader将生成的子类加载进JVM里面去.

其实, CGLib会为我们生成很多个代理类, 不单单是目标类的子类, 例如上文提到的FastClass f1, FastClass f2的子类是不同的.

  • MethodInterceptorTest$A$$FastClassByCGLIB$$65f2d708 : FastClassInfo#f1, MethodProxy的invoke()方法进行调用
  • MethodInterceptorTest$A$$EnhancerByCGLIB$$b5ca7abc$$FastClassByCGLIB$$19e0f1ba : FastClassInfo#f2, MethodProxy的invokeSuper()方法进行调用
public 

在刚开始的demo中, 如果进行如下调用, 会发生递归.

eznhancer.setCallback((MethodInterceptor) (obj, method, args1, proxy) -> {
			System.out.println("proxy start : " + proxy.getClass() + ": " + obj.getClass());
			Util.printCreateInfo(list.get(0));
			Object res2 = proxy.invoke(obj, args1); // 注意,这里将invokeSuper()换成了invoke()
			System.out.println("proxy over");
			return res2;
		});

这是因为(FastClassInfo#i1 的值为0, 因此var1为0, 刚开始的运行日志有输出 )

public 

此时的var10000就是obj, 那么流畅就成了又会去调用MethodInterceptorTest$A$$EnhancerByCGLIB$$b5ca7abc的printHi()

public 

因此当调用MethodProxy的invoke()方法时, 必须不能是MethodInterceptor#intercept的第一个obj参数.

而invokeSuper就不会有这个问题, FastClassInfo#i2的值为 14,

public 

因此执行的是var10000.CGLIB$printHi$0();这个方法

 final void CGLIB$printHi$0() {
        super.printHi();
    }

这是直接调用A的printHi()方法进行调用.

好了, 到这里分析就告一段落, 下次会分析下, cglib是如何利用ASM生成代理类的.

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值