javaWeb开发经验交流

Java--->手写一个动态代理(实战篇)

2019-01-21  本文已影响64人  haloSky_life

在上一篇中,我们对着源码看了一遍动态代理的原理,其实我们在newProxyInstance后,获取到的是一个$proxy0这个类,这个类实现了我们目标代理类相同的接口。在我们调用我们的目标方法的时候,其实是先调用这个$proxy0中的方法,然后$proxy0又调用了InvocationHandler中的invoke方法,而invoke方法中传的函数就是 ($proxy0,目标方法,参数),所以我们在InvocationHandler中不能通过参数中的obj来作为目标方法的执行对象,而是我们在创建代理类的时候,给它传了一个目标代理类,因为这个obj 是生成的代理类也就是$proxy0,如果用$proxy0去调用method,那么就会出现一个死循环。

生成的$proxy0 代理类 这里就是通过InvocationHandler来调用invoke的,因为这个$proxy0是继承了proxy这个类的,所以大家注意看是super.h.invoke,这个h 就是我们在newProxyInstance传的Matchmaker

接下里我们再来看看,这个$proxy0 这个类到底该怎么生成,我们来实践一下 :

既然要实现这个动态代理,那么有几个类是必不可少的,比如我们在最开始的时候 Proxy.newProxyInstance来获取的$proxy0这个类,那么我们自己就也得来写一个,因为我们得在这里来生成这个$proxy0 这个类

图片截不全,不好意思了哈,只能分开了

整个流程我们有这么几个步骤 :

1.生成我们的java代码

2.将生成的源代码保存到磁盘,保存为java文件

3.编译源代码,并且生成class文件

4将class文件中的内容,加载到JVM中

5.返回被代理后的代理对象

(1):我们先来看看第一步是怎么做的,生成源码:

是不是感觉很有意思,哈哈哈,类是用字符串拼接出来的 (这里很多地方我写死了,因为没想写的太复杂,有兴趣可以去研究下源码是怎么写的)

(2)将源码生成在磁盘上:

这就是我们生成的类

(3)那么现在java文件已经生成了,接下来就是把它编译成class文件了:


JavaCompiler :jdk6的特性,用来编译java的源程式,提供在运行期动态编译java代码为字节码的功能

ToolProvider:编译器的提供者

https://www.aliyun.com/jiaocheng/282144.html

(4).将class文件中的内容,加载到JVM中:

通过classLoader来做这件事,首先我们要先找到这个class文件,loader.setClassFile,这个loader是我们在newProxyInstance的时候穿的classLoader

在这里我们也自己实现了一个ClassLoader,继承ClassLoader并且需要重写它的findClass方法

首先我们先传了这个class的所在路径 这里其实就没什么好写的了,因为这个地方就是找到这个class文件,然后写进来,最后通过classLoader的defineClass方法将字节数组转换成class对象

(5).返回被代理后的代理对象:

获取构造函数对象,传入InvocationHandler,这里必须是传入InvocationHandler,因为大家还记得我们在用字符串写代码的时候吗,我们在写他的构造器的时候,我们的InvocationHandler就是它构造器的参数,大家看这段      newProxyInstance(HaloClassLoader loader, Class<?>[] interfaces,HaloInvocationHandler h),这就是为什么调目标方法会调到InvocationHandler中的invoke方法,那么到这里,真相已经大白了

最后我们来试一下,看看这样子玩到底行不行:


直接上运行结果:


小芳我爱你~

好了,这就是动态代理了,谢谢大家的浏览哟~~~ (*^▽^*)

上一篇下一篇

猜你喜欢

热点阅读