JAVA设计模式-动态代理(Proxy)示例及说明
在mybatis源码解析,一步一步从浅入深(五):mapper节点的解析文章的最后部分,我们提到了动态代理的概念,下面我们就简单了解一下动态代理。
一,概念
代理设计模式的目的就是在不直接操作对象的前提下对对象进行访问,实现这个目的得方法就是为目标对象创建一个代理(proxy),通过代理来访问目标对象。这个设计模式的优点是什么呢?代码重用,符合开闭原则。
这样解释可能会不太好理解,那么接下来就通俗的来说一下代理:
1,不知道你知不知道vpn(也就是俗称的*),在党的领导下,为了营造我国健康的的网络环境国外的一些网站在我国是无法访问的。例如:google。但是因为某些行业的特殊性需要访问这些国内不可访问的网站,那么怎么办呢?这个时候就需要代理(正向代理)了,怎么实现呢?例如:香港可以访问国内不可访问的网站,而国内却可以访问香港的网站。那么就可以这样做“国内->香港服务器(代理)->国外网站”。这里就用到了代理。
2,更通俗的例子就是,作者小的时候被狗狗追着跑,所以到现在作者看到狗狗,特别是体型庞大的狗狗的时候,就会害怕。假如一个狗狗有一天突然抢了作者的包子,那怎么办呢?那只能委托狗狗的主人,让狗狗把包子还给作者(r如果狗狗还没吃掉)。这里的主人也是扮演了代理的角色。
3,再来一个,作者是王力宏的歌迷。也一直很想点歌给王力宏唱。要怎么办?直接找他,估计没时间搭理我,最有希望的就是找他的经纪人,通过经纪人,传达我想点的歌。这个时候这个经纪人就是代理。
二,动态代理代码示例
那么接下来就以上面说到第三个例子,用代码展示一下代理模式。代理模式分为静态代理和动态代理,本文只说明动态代理。
1,王力宏是一个歌手,我们首先创建一个singer接口类,并声明一个点歌和告别的方法
1 package com.zcz.proxytest.testtwo; 2 3 public interface singer { 4 /** 5 * 根据歌名点歌 6 * @param songname 7 */ 8 public void ordersong(string songname); 9 /** 10 * 向观众告别 11 * @param audiencename 12 */ 13 public void saygoodbye(string audiencename); 14 }
2,接下来实现王力宏类,并实现接口中的两个方法。
package com.zcz.proxytest.testtwo; public class wanglihong implements singer { @override public void ordersong(string songname) { // todo auto-generated method stub system.out.println("演唱歌曲:"+songname); } @override public void saygoodbye(string audiencename) { // todo auto-generated method stub system.out.println("再见:"+audiencename); } }
3,就算我找到了经纪人(代理),那我也不能随便就叫经纪人通知(调用)王力宏(目标对象)唱歌(的方法),我还要准备一个感人肺腑的故事,但是我又不会讲故事,这个时候,经纪人就提供给了我一个模板(调用处理类,一个接口),让我按照模板编写故事(实现invoke方法)
package com.zcz.proxytest.testtwo; import java.lang.reflect.invocationhandler; import java.lang.reflect.method; public class mystoryinvocationhandler implements invocationhandler { private object object; public mystoryinvocationhandler(object o) { // todo auto-generated constructor stub this.object = o; } @override public object invoke(object proxy, method method, object[] args) throws throwable { // todo auto-generated method stub system.out.println("力宏,我是你代理经纪人:"+proxy.getclass().getname()); //处理业务 system.out.println("巴拉巴拉......(讲了一个故事)"); for(object arg:args) { system.out.println("传入的参数:"+arg); } //通知力宏做事情 method.invoke(object, args); //处理业务 system.out.println("巴拉巴拉,感谢........"); return null; } }
4,ok,到这里所有的准备工作就完成了,接下来就开始吧。
package com.zcz.proxytest.testtwo; import java.lang.reflect.proxy; public class myporxy { public static void main(string[] args) { //实例化目标对象(创造一个力宏) wanglihong lihong = new wanglihong(); //实例化调用处理类(编好的故事) mystoryinvocationhandler handler = new mystoryinvocationhandler(lihong); //接下来创建代理(经纪人) //准备一个类加载器 classloader loader = myporxy.class.getclassloader(); //获取目标对象的接口类对象数组 class<?>[] interfaces = lihong.getclass().getinterfaces(); //创建代理 singer proxy = (singer) proxy.newproxyinstance(loader, interfaces, handler); //开始点歌 proxy.ordersong("就是现在"); system.out.println("****** 歌唱中......********"); //歌唱完了,say goodbye吧 proxy.saygoodbye("zhangchengzi"); } }
5,好,现在右键-> run as -> java application。看打印结果:
力宏,我是你代理经纪人:com.sun.proxy.$proxy0 巴拉巴拉......(讲了一个故事) 传入的参数:就是现在 演唱歌曲:就是现在 巴拉巴拉,感谢........ ****** 歌唱中......******** 力宏,我是你代理经纪人:com.sun.proxy.$proxy0 巴拉巴拉......(讲了一个故事) 传入的参数:zhangchengzi 再见:zhangchengzi 巴拉巴拉,感谢........
6,看到了吗?我们不没有直接使用目标对象的方法,而是构造出一个代理对象,通过代理来访问了目标对象的方法。总结一下,想要实现动态代理需要四个关键元素
1,一个接口a
2,一个继承接口a,并实现a中抽象方法的实现类
3,一个实现了invocationhandler的调用处理类
4,调用proxy.newproxyinstance方法,获取代理类
7,ok,继续mybatis源码解析吧:mybatis源码解析,一步一步从浅入深(五):mapper节点的解析
8,虽然我们实现了一个动态代理的实例,但是你可能还更想清楚的了解动态代理的实现机制,不要着急,正好最近在找工作,有时间我们通过源代码继续深入的了解一下动态代理的实现机制。
原创不易,转载请声明出处:https://www.cnblogs.com/zhangchengzi/p/9700248.html
更多干货,请查阅。
上一篇: 使用swiper插件,全屏翻页时,某一页的页面长度超过900px,嵌套问题解决
下一篇: 使用monaco编辑器 报错Can only have one anonymous define call per script file
推荐阅读