JAVA设计模式-动态代理(Proxy)示例及说明
在Mybatis源码解析,一步一步从浅入深(五):mapper节点的解析文章的最后部分,我们提到了动态代理的概念,下面我们就简单了解一下动态代理。
一,概念
代理设计模式的目的就是在不直接操作对象的前提下对对象进行访问,实现这个目的得方法就是为目标对象创建一个代理(Proxy),通过代理来访问目标对象。这个设计模式的优点是什么呢?代码重用,符合开闭原则。
这样解释可能会不太好理解,那么接下来就通俗的来说一下代理:
1,不知道你知不知道VPN(也就是俗称的科学上网),在党的领导下,为了营造我国健康的的网络环境国外的一些网站在我国是无法访问的。例如:google。但是因为某些行业的特殊性需要访问这些国内不可访问的网站,那么怎么办呢?这个时候就需要代理(正向代理)了,怎么实现呢?例如:香港可以访问国内不可访问的网站,而国内却可以访问香港的网站。那么就可以这样做“国内->香港服务器(代理)->国外网站”。这里就用到了代理。
2,更通俗的例子就是,作者小的时候被狗狗追着跑,所以到现在作者看到狗狗,特别是体型庞大的狗狗的时候,就会害怕。假如一个狗狗有一天突然抢了作者的包子,那怎么办呢?那只能委托狗狗的主人,让狗狗把包子还给作者(r如果狗狗还没吃掉)。这里的主人也是扮演了代理的角色。
3,再来一个,作者是王力宏的歌迷。也一直很想点歌给王力宏唱。要怎么办?直接找他,估计没时间搭理我,最有希望的就是找他的经纪人,通过经纪人,传达我想点的歌。这个时候这个经纪人就是代理。
二,动态代理代码示例
那么接下来就以上面说到第三个例子,用代码展示一下代理模式。代理模式分为静态代理和动态代理,本文只说明动态代理。
1,王力宏是一个歌手,我们首先创建一个Singer接口类,并声明一个点歌和告别的方法
package com.zcz.proxyTest.testtwo;
public interface Singer {
/**
* 根据歌名点歌
* @param songName
*/
public void orderSong(String songName);
/**
* 向观众告别
* @param audienceName
*/
public void sayGoodBye(String audienceName);
}
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;
} }
代码中的method.invoke方法使用到了反射机制,想要详细了解的可以查阅:Java程序语言的后门-反射机制
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,虽然我们实现了一个动态代理的实例,但是你可能还更想清楚的了解动态代理的实现机制,不要着急,正好最近在找工作,有时间我们通过源代码继续深入的了解一下动态代理的实现机制。
相关java设计模式的文章:
JAVA设计模式-单例模式(Singleton)线程安全与效率
原创不易,转载请声明出处:https://www.cnblogs.com/zhangchengzi/p/9700248.html
JAVA设计模式-动态代理(Proxy)示例及说明的更多相关文章
- JAVA设计模式-动态代理(Proxy)源码分析
在文章:JAVA设计模式-动态代理(Proxy)示例及说明中,为动态代理设计模式举了一个小小的例子,那么这篇文章就来分析一下源码的实现. 一,Proxy.newProxyInstance方法 @Cal ...
- java --- 设计模式 --- 动态代理
Java设计模式——动态代理 java提供了动态代理的对象,本文主要探究它的实现, 动态代理是AOP(面向切面编程, Aspect Oriented Programming)的基础实现方式, 动态代理 ...
- 【设计模式】Java设计模式 - 动态代理
[设计模式]Java设计模式 - 动态代理 不断学习才是王道 继续踏上学习之路,学之分享笔记 总有一天我也能像各位大佬一样 一个有梦有戏的人 @怒放吧德德 最近工作比较忙,没啥时间学习 目录 [设计模 ...
- Java的动态代理Proxy
概念梳理: 1.什么是动态代理? 答:动态代理可以提供对另一个对象的访问,同时隐藏实际对象的具体事实.代理一般会实现它所表示的实际对象的接口.代理可以访问实际对象,但是延迟实现实际对象的部分功能,实际 ...
- Java 反射 设计模式 动态代理机制详解 [ 转载 ]
Java 反射 设计模式 动态代理机制详解 [ 转载 ] @author 亦山 原文链接:http://blog.csdn.net/luanlouis/article/details/24589193 ...
- 浅谈Java代理一:JDK动态代理-Proxy.newProxyInstance
浅谈Java代理一:JDK动态代理-Proxy.newProxyInstance java.lang.reflect.Proxy:该类用于动态生成代理类,只需传入目标接口.目标接口的类加载器以及Inv ...
- Java设计模式之代理模式(静态代理和JDK、CGLib动态代理)以及应用场景
我做了个例子 ,需要可以下载源码:代理模式 1.前言: Spring 的AOP 面向切面编程,是通过动态代理实现的, 由两部分组成:(a) 如果有接口的话 通过 JDK 接口级别的代理 (b) 如果没 ...
- 动态代理 Proxy InvocationHandler
前奏 代理模式 代理模式是常用的java设计模式,他的特征是代理类与委托类有同样的接口,代理类主要负责为委托类预处理消息.过滤消息.把消息转发给委托类,以及事后处理消息等. 代理类与委托类之间通常 ...
- java中动态代理实现机制
前言: 代理模式是常用的java设计模式,它的特征是代理类与委托类有同样的接口,代理类主要负责为委托类预处理消息.过滤消息.把消息转发给委托类,以及事后处理消息等.代理类与委托类之间通常会存在关联关系 ...
随机推荐
- 快应用 吸顶 bug
官网说, 加载页面时,所有元素的appear事件都会被触发一次.因此,需要过滤第一次的appear事件: 但是,即使设置了过滤,也无效 于是,我把show属性改成了if属性,问题就解决 如下图:
- Ubuntu16.04中用yolov3训练自己的数据集
一.配置yolo v3 参考yolo v3官网https://pjreddie.com/darknet/yolo/ 下载darknet后进行编译: git clone https://github.c ...
- Python中yield解析
小探yield 查看 python yield 文档 yield expressions: Using a yield expression in a function's body causes t ...
- HDU 5973 Aninteresting game 威佐夫博奕(Wythoff Game)
HDU 5973:http://acm.hdu.edu.cn/showproblem.php?pid=5975 题意: 有两堆石子,每次可以从一堆石子中取任意个,或者从两堆石子中取相同个数的石子.两个 ...
- POJ - 1741 - Tree - 点分治 模板
POJ-1741 题意: 对于带权的一棵树,求树中距离不超过k的点的对数. 思路: 点分治的裸题. 将这棵树分成很多小的树,分治求解. #include <algorithm> #incl ...
- POJ-1222EXTENDED LIGHTS OUT-位运算枚举模板
传送门:http://poj.org/problem?id=1222 题意:开关灯问题,一幅开关的灯中,给出一种操作,使得灯全关掉,(操作一个开关,相邻的灯也会改变) 思路:利用位运算枚举第一行: # ...
- POJ-1847 Tram( 最短路 )
题目链接:http://poj.org/problem?id=1847 Description Tram network in Zagreb consists of a number of inter ...
- ACM-ICPC 2018 沈阳赛区(网络赛)
D.Made In Heaven One day in the jail, F·F invites Jolyne Kujo (JOJO in brief) to play tennis with he ...
- poj 2649 Factovisors 对n!进行因数分解
Factovisors Time Limit: 1000MS Memory Limit: 65536K Total Submissions: 4431 Accepted: 1086 Descr ...
- JS千分位格式化方法,以及多种方法性能比较
方法一字符串版 function toThousands(num) { var result = '', counter = 0; num = (num || 0).toString(); for ( ...