动态代理有两种方式:          

  1. JDK动态代理
  2. Cglib 动态代理

JDK动态代理原理:动态字节码的原理,在内存中生成新的类。

注意:

  1. 被代理类必须实现接口。

例如  一个女孩需要找对象,她需要去找媒婆、中介。这个时候媒婆中介就可以作为一个代理对象。

接口类提供一个找对象的方法

常见设计模式-代理模式(2)

女孩有找对象的需求,需要去实现这个接口

常见设计模式-代理模式(2)

那么我们女孩类有了 ,还差一个媒婆类

常见设计模式-代理模式(2)

JDK动态代理方法 ,需要去实现  InvocationHandler 类。

接下来我们测试一下

常见设计模式-代理模式(2)

通过Debug发现 :

常见设计模式-代理模式(2)

实际上调用的类,并不是媒婆类,而是一个$proxy0的类。

随后,满怀好奇心的我,去将这个在内存中  $proxy0 的这个类,下载到本地后发现

常见设计模式-代理模式(2)

常见设计模式-代理模式(2)

这个$proxy0 实际上是实现了 Person接口,这也就是说为什么动态代理必须要有接口的原因所在

然后传入进来一个 InvocationHandler 的实例,去调用invode方法

常见设计模式-代理模式(2)

随后它将这个接口内的所有方法都作为今天方法保存下来,并且排序。

常见设计模式-代理模式(2)

然后在调用和Person接口一模一样的方法名称,m3就是Person接口中的findLove()方法。

那么这个super.h 又是哪里来的呢?

我顺着&proxy0继承的父类 Proxy 找下去

常见设计模式-代理模式(2)

发现就是我们之前实现InvocationHandler的媒婆类的这个实例来调用了invoke方法

常见设计模式-代理模式(2)

这里还运用到了反射 去调用method.invoke()方法。

找到了原理,接着我就仿造JDK动态代理的手写了一段动态代理。

还是以当前的例子  女孩需要媒婆给她找对象

这时 媒婆就成为了女孩的代理人,为女孩的需要物色对象。

我们按这个需求去编写代码

首先需求是 女孩类  媒婆类  代理类 以及 InvocationHandler类 还有一个ClassLoader类

为什么要创建这些类,请仔细往下看

常见设计模式-代理模式(2)

我们创建一个 KyInvocationHandler 类,提供Invoke方法。

常见设计模式-代理模式(2)

接着我们创建一个媒婆类,实现KyInvocationHandler 类,去代理女孩的要求。

常见设计模式-代理模式(2)

在这时我们可以看到,Kyproxy代理类 生成代理实例,代理 媒婆帮女孩找对象的方法

KyProxy.newProxyInstance(new KyClassLoader(), clazz.getInterfaces(), this);

常见设计模式-代理模式(2)

不同的媒婆实例,去代理不同的女孩寻找对象的方法。

this 就是当前媒婆的具体实例,去执行女孩找对象的需求的方法

clazz.getInterfaces() 就是被代理类接口  也就是女孩类 实现的Person的接口,用来声明女孩需要做什么。

new KyClassLoader()  是我们手写的类加载器

       KyClassLoader类

       作用就是  寻找我们这个动态代理的代理类$proxy0   相信大家也都熟悉 $proxy0 这个类。

       作用时间  在 媒婆执行女孩找对象的需求时,我们去找到代理类 $proxy0  ,

      动态代理每一个媒婆  去帮每一个女孩找对象的需求。 

newProxyInstance 方法就是KyClassLoader类寻找到代理类$proxy0 后 

       生成一个$proxy0代理对象 来代理媒婆需要做的事情。

其实JDK底层原理也是这样,在内存中生成一个$proxy类,使用这个类的实例去调用媒婆类的invoke方法。

常见设计模式-代理模式(2)

而媒婆类的invoke方法执行的时候,就是调用被代理对象 女孩类需要找对象的方法。

那么具体 $proxy在内存中是怎么生成的呢?

我想到其实应该也就是用代码去生成代码

如下所示:

常见设计模式-代理模式(2)

常见设计模式-代理模式(2)

测试如下:

常见设计模式-代理模式(2)

到这里,底层动态代理的原理就搞清楚了。

相关文章: