动态代理与静态代理使用类图来进行对比

最近在知乎上看了几篇质量很高的文章,虽然都是一些老问题,但是理解都比较有新意。动态代理这个技术点在学Spring的时候就接触到,当时对这个技术点并没有什么深刻的印象,都是看别人的文章囫囵吞枣理解了下。今天看了这篇文章准备《轻松学,Java 中的代理模式及动态代理》,这些文章虽然讲的很详细并且附上了示例的代码,但是不如类图理解起来方便,遂用类图记录下自己的理解,建议读者可以先看代码再看类图。


一些概念的说明
依赖:在类图中如果类A中含有类型B的成员变量,则A依赖于B
关联:在类图中如果类A中方法中的参数有用到类型B,则A关联于B
这些概念不一定正确,知道表示的意思即可,如果有错误,请在评论中指出,因为我对UML也没有进行过深入的学习。


静态代理

  • Movie: 这是一个接口,里面有一个play()方法,相当于播放电影的操作。
  • RealMovie: 实现了Movie接口,真正实现电影播放的类。
  • Cinema: 这个是电影院,相当于代理商,代理播放各种电影。

上面的关系并不复杂,从中我们可以看出Cinema可以代理所有类型的电影。但是电影院如何想卖商品,在不改动代码的前提下它就没法代理提供物品的销售商,这个缺点是很明显的,下面我们来看看动态代理是如何解决这个问题的。

动态代理

这里只介绍主要的业务类:
* SellWine: 代表酒类的商品,其中有一个mainJiu()方法,表示该就被卖掉
* MaotaiJiu: 具体的品牌,这里是茅台酒
* GuitaiA: 该类表示柜台,可以出售商品
动态代理的类图有点复杂,因为它引用了Java中的Proxy类、InvocationHandler接口。但我将两个类图都做了划分,一部分是销售商(被代理的类),一部分是代理商(代理类)。我们发现两张类图中的销售商结构都是一样的,最大的不同在代理商这一块。在这里我们将GuitaiA可以跟静态代理中的Cinema做对比,上面的Proxy以及InovationHandler我们先不要去关注,因为这些类会影响我们的视线。我们发现GuitaiA不依赖SellWine接口,依赖的是Object,这就是动态代理可以代理很多类型销售商的原因。静态代理Cinema需要依赖RealMovie的原因是因为我们必须要拥有一个RealMovie的对象才能调用其中的play()方法。但是动态代理调用方法并不需特定类型的对象,上面的Object就表明传入任意的对象我都能触发它接口中的方法,这种功能的实现主要用到了反射的技术(这里是实现了InvocationHandler接口)。虽然GuitaiA代理了MaotaiJiu,但是我们调用的入口肯定还是SellWine引用一个具体的类,然后调用mainJiu()方法。那么这个具体的类是怎么来的呢?这里是由Proxy来生成的。编写Java程序时我们先编写.java文件,然后编译成.class文件,jvm将我们的.class文件转换为字节码加载到内存中,在需要使用的时候再实例化。上述这是比较常见的创建对象的方式,但是如果有些类实现并不能由.java文件来定义,这个时候我们可以在内存中直接构造类的字节码信息,当然这是比较复杂的实现方式,我也不是很清楚构造的方式,这里知道有这种技术即可。


上述可以看出动态代理的实现方式并不难,难点在于底层的实现方式,不过这些太底层的东西日常开发中很难用到,一般都出现在开源项目的源码中。

发表评论

电子邮件地址不会被公开。 必填项已用*标注