动态代理有两种方式:
- JDK动态代理
- Cglib 动态代理
JDK动态代理原理:动态字节码的原理,在内存中生成新的类。
注意:
- 被代理类必须实现接口。
例如 一个女孩需要找对象,她需要去找媒婆、中介。这个时候媒婆中介就可以作为一个代理对象。
接口类提供一个找对象的方法
女孩有找对象的需求,需要去实现这个接口
那么我们女孩类有了 ,还差一个媒婆类
JDK动态代理方法 ,需要去实现 InvocationHandler 类。
接下来我们测试一下
通过Debug发现 :
实际上调用的类,并不是媒婆类,而是一个$proxy0的类。
随后,满怀好奇心的我,去将这个在内存中 $proxy0 的这个类,下载到本地后发现
这个$proxy0 实际上是实现了 Person接口,这也就是说为什么动态代理必须要有接口的原因所在
然后传入进来一个 InvocationHandler 的实例,去调用invode方法
随后它将这个接口内的所有方法都作为今天方法保存下来,并且排序。
然后在调用和Person接口一模一样的方法名称,m3就是Person接口中的findLove()方法。
那么这个super.h 又是哪里来的呢?
我顺着&proxy0继承的父类 Proxy 找下去
发现就是我们之前实现InvocationHandler的媒婆类的这个实例来调用了invoke方法
这里还运用到了反射 去调用method.invoke()方法。
找到了原理,接着我就仿造JDK动态代理的手写了一段动态代理。
还是以当前的例子 女孩需要媒婆给她找对象
这时 媒婆就成为了女孩的代理人,为女孩的需要物色对象。
我们按这个需求去编写代码
首先需求是 女孩类 媒婆类 代理类 以及 InvocationHandler类 还有一个ClassLoader类
为什么要创建这些类,请仔细往下看
我们创建一个 KyInvocationHandler 类,提供Invoke方法。
接着我们创建一个媒婆类,实现KyInvocationHandler 类,去代理女孩的要求。
在这时我们可以看到,Kyproxy代理类 生成代理实例,代理 媒婆帮女孩找对象的方法
KyProxy.newProxyInstance(new KyClassLoader(), clazz.getInterfaces(), this);
不同的媒婆实例,去代理不同的女孩寻找对象的方法。
this 就是当前媒婆的具体实例,去执行女孩找对象的需求的方法。
clazz.getInterfaces() 就是被代理类接口 也就是女孩类 实现的Person的接口,用来声明女孩需要做什么。
new KyClassLoader() 是我们手写的类加载器
KyClassLoader类
作用就是 寻找我们这个动态代理的代理类$proxy0 相信大家也都熟悉 $proxy0 这个类。
作用时间 在 媒婆执行女孩找对象的需求时,我们去找到代理类 $proxy0 ,
动态代理每一个媒婆 去帮每一个女孩找对象的需求。
newProxyInstance 方法就是KyClassLoader类寻找到代理类$proxy0 后
生成一个$proxy0代理对象 来代理媒婆需要做的事情。
其实JDK底层原理也是这样,在内存中生成一个$proxy类,使用这个类的实例去调用媒婆类的invoke方法。
而媒婆类的invoke方法执行的时候,就是调用被代理对象 女孩类需要找对象的方法。
那么具体 $proxy在内存中是怎么生成的呢?
我想到其实应该也就是用代码去生成代码
如下所示:
测试如下:
到这里,底层动态代理的原理就搞清楚了。