对于动态代理我想应该大家都不陌生,就是可以动态去代理实现某个接口的类来干一些我们自己想要的功能,但是在字节码层面它的表现是如何的呢?既然目前刚好在研究字节码相关的东东,有必要对其从字节码角度来审视一下。
下面先来实现一个动态代码的程序:
先新建一个接口:
接下来定义一个具体的实现类:
然后再建议一个动态代理类,如下:
然后在里面要持有要代理的真实对象,如下:
然后咱们来调用一下看下效果:
那用Proxy生成代理对象都传些啥呢,第一个参数是加载动态对象的classloader,这里传加载RealSubject类的类加载器,如下:
第二个参数为生成动态对象所实现的接口,这里直接拿真实对象的接口既可:
最后一个参数则传InvocationHandler对象,如下:
接下来运行一下:
另外注意一下,其中动态生成的subject接口的对像真实类型其实是一个代理类,咱们可以打印一下:
其中“com.sun.proxy.$Proxy0”在是运行期动态生成的代理对像,而不是我们自己编定的类,那该对象对应的字节码信息要怎么看呢?所以第一个难题就出来了,要想知道它的字节码信息,就必须知道它是如何生成的,所以别无它法,只能硬着头皮去分析源代码才能知晓,所以接下来去源码来寻找蛛丝马迹:
根据调用咱们就必须跟到Proxy中的newProxyInstance()方法去查看喽,走进去!
其中先对这三个参数再来瞅一下:
接下来开始寻找线索,注意:只看跟我们预期相符的主要代码,一些无关的直接略过,发现有一处貌似挺关键的,如下:
所以跟进去:
既然上面的这个关键注释可以看刚我们所要查找的代理类的对像很显然跟这个缓存有关,所以跟进去:
但是我们会发现这个方法中貌似没有太多线索,这里就不贴出该方法的所有源码了, 不过,我们可以将焦点先定位到方法结果的返回上,也就是这:
所以接下来就得知道supplier对像是如何创建出来的,所以可以往下找就会发现有这样一段代码:
然后咱们就进入这个Factory去瞅一眼:
那。。没有办法的时候可以用debug的方式来走一遍流程,所以下面来debug一下:
然后往里跟,因为代理对像的生成就是在这个方法里面:
继续往里跟:
然后在这里面单步调试时会到我们之前分析的Factory生成这块:
此时则生成了一个factory对象,接着往下到关键部位:
此时将factory赋值给了supplier对象了,接着往下又会回到循环开始处:
此时再往下单步走一步,就会发现我们的预期要的东东啦,如下:
所以整个分析的焦点还得放在supplier.get()方法来,而它是由Factory赋值的,所以又回到了之初我们分析的Factory对像啦,所以咱们在Factory里面的get()方法打个断点继续来找寻:
所以跟进去看一下:
此时又回到了Proxy代理类了,咱们往下单步跟踪到关键处如下:
线索最终找到,也就是最终代理类的生成是ProxyGenerator这个类来实现的,最终得到一个二进制的字节码对象,咱们跟进去瞅一下这个类:
然后定位到指定的方法就可以发生如何来生成代理类的字节文件出来了,如下:
所以现在就是想办法将这个flag设置为true既可,那看一下这个flag:
所以接下来咱们来设置一下该系统属性看下效果:
咱们来运行一下:
下次就来分析该字节码!