代理(Proxy)设计模式
概述
正文开始之前我们先考虑一个问题:什么叫做代理(Proxy)
?
按照维基百科
定义:
代理(英语:Proxy)也称网络代理,是一种特殊的网络服务,允许一个网络终端(一般为客户端)通过这个服务与另一个网络终端(一般为服务器)进行非直接的连接。一些网关、路由器等网络设备具备网络代理功能。一般认为代理服务有利于保障网络终端的隐私或安全,防止攻击。
通俗讲代理
就类似一个连接在客户端和服务器之间的桥梁,连通客户端和服务器之间的请求和响应,代理的存在一方面可以保护服务器的安全,在代理部分可以对请求信息进行过滤,隔绝一部分非法的请求信息吗,另一方面可以提高用户的访问速度,其具体功能可以借助下边的图来帮助理解。
我们再举个例子,突然某一天你需要见某个身份显赫的王总和他谈一个项目,一般来说你是不可能直接去见人家的,但王总必然是有秘书的,你可以提前跟秘书说,秘书代为向王总转达。王总如果对这个项目感兴趣会让秘书通知你。整个过程中,你就相当于那个客户端,秘书相当于代理,王总就相当于服务器。
如果你理解上述代理
的概念,那么代理设计模式
也就不难理解了。代理设计模式
就是对上边上客户端-代理-服务器
三者链式关系的一种抽象,进而应用到软件开发中的一种通用设计模式。
代理设计模式有如下三个优点:
- 保护真实对象
- 让对象职责更加明确
- 易于扩展
在java开发中代理设计模式有三种实现方法:
- 静态代理
- 动态代理 jdk实现
- 动态代理 cglib实现
下边我们分三种情况对这三种代理设计模式的实现进行讨论和分析
静态代理
UML类图
KeHu
:客户端MiShhu
:中介LaoZong
:服务器GongNeng
:服务器和中介要同时实现的功能接口
代码实现
GongNeng
的java代码:
/**
* @program: TestBlog
* @description:
秘书和老总都要实现的功能接口
* @author: vcjmhg
* @create: 2019-10-07 16:31
**/
public interface GongNeng {
public void ZuoShengYi();
public void eat();
}
Kehu
的java代码
/**
* @program: TestBlog
* @description:
客户相当于客服端
* @author: vcjmhg
* @create: 2019-10-07 16:31
**/
public class KeHu {
public static void main(String[] args) {
MiShu miShu=new MiShu();
miShu.ZuoShengYi();
}
}
MiShu
的java代码
/**
* @program: TestBlog
* @description:
* @author: vcjmhg
* @create: 2019-10-07 16:31
**/
public class MiShu implements GongNeng{
private LaoZong laoZong=new LaoZong();
public void ZuoShengYi() {
System.out.println("秘书:请问您预约来吗?");
laoZong.ZuoShengYi();
System.out.println("秘书备注访客信息");
}
public void eat() {
System.out.println("秘书:请问您预约来吗?");
laoZong.eat();
System.out.println("秘书备注访客信息");
}
}
LaoZong
的java代码:
package proxy.staticproxy;
/**
* @program: TestBlog
* @description:
* @author: vcjmhg
* @create: 2019-10-07 16:31
**/
public class LaoZong implements GongNeng{
public void ZuoShengYi() {
System.out.println("老总:谈个小项目!!");
}
public void eat() {
System.out.println("老总:吃饭!!");
}
}
运行结果为:
秘书:请问您预约来吗?
老总:谈个小项目!!
秘书备注访客信息
Process finished with exit code 0
代码地址
详细的代码可以参看github的上的代码
静态代理的不足
毫无疑问静态代理作为最容易实现或者说最直观的的代理设计模式的实现方式,代理模式具有的优点它必然也具有,但另一方面它也有许多缺点:
- 代理类和委托类实现了相同的接口,代理类通过委托类实现了相同的方法。这样就出现了大量的代码重复。如果接口增加一个方法,除了所有实现类需要实现这个方法外,所有代理类也需要实现此方法。增加了代码维护的复杂度。
- 代理对象只服务于一种类型的对象,如果要服务多类型的对象。势必要为每一种对象都进行代理,静态代理在程序规模稍大时就无法胜任了。
为了解决该问题我们引入了动态代理
动态代理之jdk实现
UML类图
Client
:客户端MiShhu
:中介LaoZong
:服务器GongNeng
:服务器和中介要同时实现的功能接口
代码实现
Client
的java代码:
/**
* @program: TestBlog
* @description:
* @author: vcjmhg
* @create: 2019-10-07 17:04
**/
public class Client {
public static void main(String[] args) {
//第一个参数:反射时使用的类加载器
//第二个参数:Proxy需要实现什么接口
//第三个参数:通过接口对象调用方法时,需要调用哪个类的invoke方法
GongNeng gongneng = (GongNeng) Proxy.newProxyInstance(Client.class.getClassLoader(), new Class[]{GongNeng.class}, new MiShu());
gongneng.eat();
}
}
GongNeng
的java代码:
public interface GongNeng {
public void ZuoShengYi();
public void eat();
}
MiShu
的java代码
/**
* @program: TestBlog
* @description:
* @author: vcjmhg
* @create: 2019-10-07 16:56
**/
public class MiShu implements InvocationHandler {
private LaoZong laozong=new LaoZong() ;
//代理类针对被代理对象类似的功能不需要重复实现多次
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println("预约时间");
Object result = method.invoke(laozong, args);
System.out.println("记录访客信息");
return result;
}
}
LaoZong
的java代码:
/**
* @program: TestBlog
* @description:
* @author: vcjmhg
* @create: 2019-10-07 16:49
**/
public class LaoZong implements GongNeng{
private String name;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public void ZuoShengYi() {
System.out.println("老总:谈生意");
}
public void eat() {
System.out.println("老总:吃饭!!");
}
}
运行结果为:
预约时间
老总:吃饭!!
记录访客信息
Process finished with exit code 0
利用JDK实现动态代理的优点
相比与静态代理,利用JDK实现动态代理的方式实现了代理类和功能接口之间的解耦。对于委托类如果增加某个方法,对于代理类代码几乎可以不变,减少了代码的复杂性,使其更加易于维护。另一方面在代理不同类型对象时可以实现代码一定程度的复用。
利用JDK实现动态代理的不足
但是该方法实现动态代理也有一定不足,由于其内部借助反射实现代理设计模式,系统开销大效率低。而且其委托类仍需实现功能接口,代码耦合性还是不够低。
代码地址
详细的代码可以参看github的上的代码
动态代理之cglib实现
UML类图
Client
:客户端MiShhu
:中介LaoZong
:服务器
代码实现
Client
的java代码
public class Client {
public static void main(String[] args) {
Enhancer enhancer = new Enhancer();
enhancer.setSuperclass(LaoZong.class);
enhancer.setCallback(new MiShu());
LaoZong laozong = (LaoZong) enhancer.create();
laozong.chifan();
}
}
MiShu
的java代码:
public class MiShu implements MethodInterceptor{
public Object intercept(Object arg0, Method arg1, Object[] arg2, MethodProxy arg3) throws Throwable {
System.out.println("预约时间");
Object result = arg3.invokeSuper(arg0, arg2);
System.out.println("备注");
return result;
}
}
LaoZong
的java代码:
public class LaoZong {
public void chifan() {
System.out.println("吃饭");
}
public void mubiao() {
System.out.println("目标");
}
运行结果为:
预约时间
吃饭
备注
Process finished with exit code 0
利用cglib实现动态代理的优点
通过cglib方式几乎完美的解决来jdk方式所具有的缺点一方面cglib方式内部是通过字节码方式实现动态代理,效率高,执行速度快;另一方面,该方式解耦了委托类和功能接口之间的耦合,提高了代码的灵活性。
代码地址
详细的代码可以参看github的上的代码
代理(Proxy)设计模式的更多相关文章
- JAVA设计模式-动态代理(Proxy)示例及说明
在Mybatis源码解析,一步一步从浅入深(五):mapper节点的解析文章的最后部分,我们提到了动态代理的概念,下面我们就简单了解一下动态代理. 一,概念 代理设计模式的目的就是在不直接操作对象的前 ...
- JAVA设计模式-动态代理(Proxy)源码分析
在文章:JAVA设计模式-动态代理(Proxy)示例及说明中,为动态代理设计模式举了一个小小的例子,那么这篇文章就来分析一下源码的实现. 一,Proxy.newProxyInstance方法 @Cal ...
- 100行代码让您学会JavaScript原生的Proxy设计模式
面向对象设计里的设计模式之Proxy(代理)模式,相信很多朋友已经很熟悉了.比如我之前写过代理模式在Java中实现的两篇文章: Java代理设计模式(Proxy)的四种具体实现:静态代理和动态代理 J ...
- 初识代理——Proxy
无处不在的模式——Proxy 最近在看<设计模式之禅>,看到代理模式这一章的时候,发现自己在写spring项目的时候其实很多时候都用到了代理,无论是依赖注入.AOP还是其他,可以说是无处不 ...
- 代理(Proxy)和反射(Reflection)
前面的话 ES5和ES6致力于为开发者提供JS已有却不可调用的功能.例如在ES5出现以前,JS环境中的对象包含许多不可枚举和不可写的属性,但开发者不能定义自己的不可枚举或不可写属性,于是ES5引入了O ...
- 深度揭秘ES6代理Proxy
最近在博客上看到关于ES6代理的文章都是一些关于如何使用Proxy的例子,很少有说明Proxy原理的文章,要知道只有真正掌握了一项技术的原理,才能够写出精妙绝伦的代码,所以我觉得有必要写一篇关于深刻揭 ...
- Webpack代理proxy配置,解决本地跨域调试问题,同时允许绑定host域名调试
Webpack代理proxy配置,解决本地跨域调试问题,同时允许绑定host域名调试 会撸码的小马 关注 2018.05.29 17:30* 字数 212 阅读 1488评论 0喜欢 2 接到上一章, ...
- 浅谈Java代理一:JDK动态代理-Proxy.newProxyInstance
浅谈Java代理一:JDK动态代理-Proxy.newProxyInstance java.lang.reflect.Proxy:该类用于动态生成代理类,只需传入目标接口.目标接口的类加载器以及Inv ...
- java动态代理--proxy&cglib
大纲 代理 proxy cglib 小结 一.代理 为什么要用代理?其实就是希望不修改对象的情况下,增强对象. 静态代理: 静态代理模式,需要代理类和目标类实现同一接口,代理类的方法调用目标类的方法, ...
- 设计模式--代理(Proxy)模式
在公司,经常性听到采购部的人说采购某样东材料,采购不了,需要通过代理商才可以.以前Insus.NET也做有一个练习<找人办事,代理设计模式(Proxy)>http://www.cnblog ...
随机推荐
- Linux系统简介以及基本操作(一)
Linux简介(操作系统) Linux发展史(了解) Linux出现于1991年,是由芬兰赫尔辛基大学学生李纳斯·托瓦兹(Linus Torvalds)偶然发现的,他当时是为了方便下载学校网站的一些视 ...
- centos安装oracle11g
1.1 安装依赖,创建用户和目录 参考http://www.cnblogs.com/gaojun/archive/2012/11/22/2783257.html yum -y install binu ...
- Linux中JDK安装配置
安装jdk 1)下载地址:https://www.oracle.com/technetwork/java/javase/downloads/index.html 我选择jdk1.8版本 2)上传至服务 ...
- hihocoder 1523 数组重排2+思维
参考:http://blog.csdn.net/howardemily/article/details/74991367 题意:每次可以移动数组中的一个数到数组的最左边,问最少操作数,使得数列升序: ...
- HDU 5324 Boring Class CDQ分治
题目传送门 题目要求一个3维偏序点的最长子序列,并且字典序最小. 题解: 这种题目出现的次数特别多了.如果不需要保证字典序的话直接cdq就好了. 这里需要维护字典序的话,我们从后往前配对就好了,因为越 ...
- JavaScript new的运行过程
参考 MDN网站的运算符 https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Operators/new new 运算符 ...
- ASP.NET MVC实现依赖注入
在java的spring中有自动注入功能,使得代码变得更加简洁灵活,所以想把这个功能移植到c#中,接下来逐步分析实现过程 1.使用自动注入场景分析 在asp.net mvc中,无论是什么代码逻辑分层, ...
- 【Offer】[13] 【机器人的运动范围】
题目描述 思路分析 Java代码 代码链接 题目描述 地上有一个m行和n列的方格.一个机器人从坐标0,0的格子开始移动,每一次只能向左,右,上,下四个方向移动一格,但是不能进入行坐标和列坐标的数位之和 ...
- CentOS配置服务开机自启
本例子以nginx作为举例: CentOS7中 以systemctl 替代了chkconfig 进行服务的管理, 默认在CentOS6 中控制服务开机自启,是在vim /etc/rc.d/rc.loc ...
- Java第三次作业第一题
1.[请复制本程序,作为java程序代码,进行编译,补充填写缺失代码部分,并实现题目要求功能,从而获得空白填写所需的内容.] 编写无限计时程序,从0:1开始计时,一直循环计时,计时到60秒,变为1:0 ...