喵星之旅-沉睡的猫咪-代理模式
代理是什么?
代理模式是23种设计模式之一,属于结构型设计模式,主要为静态代理和动态代理。
在java中有句话--“一切都是对象”,在struts中有句话--“一切都是拦截器”,而在结构型设计模式中也有句话--“一切都是适配器”。所以这种设计模式和其他的结构型设计模式相似度还是很高的,主要区别在我们的意向和一些常用的方式风格,同样的代码可以有不同的解读,所以不同人看到的设计模式可能是不同的。
代理模式主要是对于一个对象的访问,我们依托于另一个对象(适配器都这样)。我们称之为代理。和mvc的分层类似,c是额外多出来的,这里就是代理类是额外多出来的,并且实现了调用者和被代理对象的分割。除了这个分割以外,代理类还可以进行功能的增强处理,就像spring的aop。
我们最上层应该是一个实体对应的接口,在接口下有具体实现类。每一个实现类都有一个单独的代理类就是静态代理。如果一个接口对应一个代理类,下面的所有实现类都可以通过这个代理类实现代理,就是动态代理。
静态代理
代理类只实现一个对象的代理。一般是通过合成复用实现,即代理类内置一个属性就是被代理类,当然可以使用对象的任何功能。我们在使用的时候只知道代理的存在和相应的功能,对于被代理对象知之甚少。调用方法来自代理类,更像适配器。
动态代理(jdk实现方式)
代理对象只需要一个,就可以实现一个接口下所有实现类的代理。使用时是需要通过接口能力来使用的,代理类只是一个实现功能的手段,并不是直接面对代理类,调用方法来自接口。
动态代理主要是两种方式,下面是jdk的方式。下面是一个媒婆的中介代理,随便什么人,只要是人这个接口的实现类都可以通过这个媒婆实现代理。
上面实体类接口无须多讲,主要在于这个代理类如何来做。我们可以先看一下jdk中代理类java.lang.reflect.Proxy。
我们可以先创建这个代理类,写上获得对象的方法。然后再看如何写里面的内容。
第一步先分析
Proxy.newProxyInstance(Foo.class.getClassLoader(),new Class<?>[] { Foo.class },handler);
我们需要三个东东,第一个是foo类,问题在于这个类可能不存在(因为应该支持扩展,也就是有新的实现类出现,是写代理类时不存在的),所以需要传入参数string,通过反射生成对象获得类。
选中区域就是第一个需要的参数。
上图为Proxy.newProxyInstance的注释,标红部分为第二个参数解释,使用jdk必须实现接口的方式扩展,所以是面向接口的,这个接口就是我们实现类实现的接口,第一个参数获取的对象可以进而得到第二个参数。
至于第三个参数就比较特殊了,叫InvocationHandler。这就是jdk动态代理比较特殊的地方,除了需要接口的设计以外,代理类必须是这个类型的,所以我们的代理类要实现这个接口:
至于接口的内容稍后再说,我们先看创建对象第三个参数,如果实现了这个接口那么this刚好是这个类型,并且就是我们需要的,如果我们这个类实现了这个接口,this就是第三个参数。
至此,我们创建对象的方法就完成了,但是为了完成创建对象,我们实现了一个接口,问题就是这个接口是什么东东?
invoke我们查阅字典之后是某种行动,也就是执行方法的一般描述,方法中的invoke类似于类中的Object。我们说过代理除了隔离,实现创建对象以外,还有功能的增强,类似于aop,也类似于过滤器,就是通过这个方法,使用和过滤器类似。
这个家伙有三个参数:第三个比较明确,就是方法入参,因为执行的方法是一般化的抽象,不知道具体情况,只能用数组方式定义;第二个也比较明显看出含义,就是要执行的方法,至于怎么用再说;第一个需要参考说明(调用该方法的代理实例),我们直接给出结果吧,就是不用管他。然后就是如何实现原有的方法执行,知道这个我们才能够进行增强处理。我们观察这个方法是返回object,也就是应该找寻method中返回这个类型的可能性最大。我们可以找到2个,逐一实验观察是否能有需要的,将会发现method.invoke这个家伙需要参数
第二个参数刚好是我们拥有并且不知道该怎么用的,没错!就是这个方法,那第一个参数呢?宝宝需要一个叫英汉词典的东东%>_<%,我们也可以去猜测一下有什么可能?被代理的实例?当前对象?还有第一个入参呢?好吧,最后的结果是被代理的实例,不过这个怎么能获得?原来我创建对象的时候应该吧那个对象传过来,怎么传呢?最简单的就是保存在成员变量中:
就是这么干的O(∩_∩)O~
至于如何增强就不说了,和面向切面、过滤器、拦截器都相似。
我们可以写这样的一个测试类
只需要定义接口,就可以动态扩展,但是这个好像没有绑定接口哦,岂不是所有接口都可以用这一个代理类?是的!是的!是的!但是,对于不同的接口我们选择的增强处理应该是不同的,所以应该有不同的代理类,不同代理类的区别就在增强处理,如果不需要这个处理的确可以一个代理类实现所有接口的代理。
由于动态代理在程序写完之后,会根据我们的程序自己写新的类,实现功能扩展,所以特别受到框架开发人员喜爱,成为了框架中必不可少的存在。
作者:喵星兔
出处:https://www.cnblogs.com/kittybunny/
喵星之旅:https://www.cnblogs.com/kittybunny/p/12148641.html
我的视频:https://space.bilibili.com/518581788
更多内容:不咬人的小兔子
本博客所有文章仅用于学习、研究和交流目的,欢迎非商业性质转载。
我是兔子,我会喵,我叫喵星兔~~