Java设计模式 —— 代理模式
15 代理模式
15.1 代理模式概述
Proxy Pattern: 给某一个对象提供一个代理或占位符,由代理对象来控制对原对象的访问。
代理对象是客户端和目标对象的之前的桥梁,它接收来自客户端的请求并转发给目标对象,去掉客户端不能看到的内容或添加额外的服务。为了保证客户端使用的透明性,代理对象和原对象需要实现相同的接口。
代理模式结构图如下所示:
15.2 代理模式实现
15.2.1 抽象主题接口
代理对象和原访问对象都需要实现该接口,使得任何使用真实主题对象的地方都可以使用代理对象,客户端也可以针对抽象层编程。
public interface Subject {
public void request();
}
15.2.2 真实主题类
public class RealSubject implements Subject {
public void request() {
// 业务逻辑代码
}
}
15.2.3 代理类
代理类中包含对真实主题的引用,可以把客户端请求转发给真实主题并将请求结果返回给客户端。同时,代理类在将请求转发给真实主题之前和之后还可以执行一些其他操作,增加客户端需要的额外服务。
public class Proxy implements Subject {
private Subject realSubject = new RealSubject();
public void request() {
preRequest();
// 请求转发给真实主题
realSubject.request();
postRequest();
}
public void preRequest() {
// 转发前业务代码
}
public void postRequest() {
// 转发后业务代码
}
}
15.2.4 客户端调用
public class Client {
public static void main(String[] args) {
// 针对抽象层编程, 具体类名 Proxy 可以在配置文件写入
// 该代码等价于 Subject subject = new Proxy();
Subject subject = (Subject) XMLUtil.getBean();
// 通过代理类访问真实主题
subject.request();
}
}
15.3 远程代理
Remote Proxy: 远程代理使得客户端可以访问远程主机上的对象并调用其方法。
远程代理示意图如下所示:代理对象负责接收客户端请求,并通过网络通信访问远程对象,代理对象对于客户端是透明的。

15.3.1 Java RMI
Method Invocation是Java对象间通信最基本的方法,对于同一虚拟机内的对象通信,简单的方法调用即可实现。而对于位于不同主机上的虚拟机中的对象之间通信,则需要一套远程方法调用的机制,帮助我们获得远程主机上对象的引用,并在自己的虚拟机中像使用自己的对象一样使用它。
RMI 允许我们调用远程对象上的方法,可以将 Java 对象作为参数传递,并获得 Java 对象作为返回值。因此 RMI 需要使用对象序列化,在网络上传输对象,必要时还可以使用动态类加载和安全管理器安全地传输 Java 对象。
15.3.2 Stubs and skeletons
Java RMI 主要工作流程如下所示:

Stub: 被称为 ”存根“,保存在客户端,即代理模式中出现的代理类,其负责与远程对象通信
Skeletons: 被称为 ”骨架“,保存在服务端,用于接收 Stub 发送过来的请求,调用服务端对象的方法,并将返回值发送给 Stub
15.3.3 Java RMI Server
Java RMI 服务端主要是构建一个可以通过网络传输的结果类和一个可以被远程访问的目标类,同时需要将该目标类的实例对象注册到 RMI Registry
// 自定义远程接口, 需要继承自 Remote
public interface RemoteObject extends Remote {
public String remoteHello() throws RemoteException;
}
/**
* 这个例子没用构建结果类,直接使用 String 类(可序列化)
* 如果要自定义对象结果类,只需要实现 Serializable 接口即可
*/
public class RemoteObjectImpl extends UnicastRemoteObject implements RemoteObject {
// 空的构造方法,不能使用默认构造,因为需要抛出异常
protected RemoteObjectImpl() throws RemoteException {}
public String remoteHello() throws RemoteException() {
// 业务逻辑代码
// return String 对象
}
}
// 注册
public class RMIServer {
public static void main(String[] args) throws RemoteException, AlreadyBoundException, MalformedURLException {
try {
Registry registry = LocateRegistry.createRegistry(1900);
//实例化远程对象类
RemoteObject remoteObject = new RemoteObjectImpl();
//通过 Naming.bind()方法绑定别名与远程对象
Naming.bind("rmi://127.0.0.1:1900/remoteService", remoteObject);
}
catch(Exception e) {
e.printStackTrace();
}
}
}
15.3.4 Java RMI Client
public class RMIClient {
public static void main(String[] args) throws RemoteException, NotBoundException {
Registry registry = LocateRegistry.getRegistry("127.0.0.1", 1900);
//打印注册中心的远程对象列表
System.out.println(Arrays.toString(registry.list()));
//通过别名获取远程对象代理 stub 并调用远程对象的方法
RemoteObject stub = (RemoteObject) registry.lookup("remoteService");
System.out.println(stub.remoteHello());
}
}
15.4 动态代理
在传统的代理模式中,客户端通过代理对象调用真实主题中的方法。这种情况下,代理类和真实主题类都事先存在,且代理方法也明确指定。每个代理类经过编译之后生成字节码文件,其实现的接口和代理的方法均被固定,这种代理模式被称为静态代理。
静态代理扩展非常不便,无论是需要给不同的主题增加代理还是给同一主题代理不同方法,都需要增加新的代理类,或者修改原代码(不符合开闭原则)。
动态代理(Dynamic Proxy)技术可以让系统在运行时根据需要动态创建代理类,使同一个代理类能够代理多个不同的真实主题类和不同方法。
15.4.1 动态代理实现
构建两个不同的真实主题接口
public interface SubjectA {
public Boolean proxyMethod1(String s); public String proxyMethod2(String s);
} public interface SubjectB {
public String proxyMethod1(String s);
}
构建具体主题类
public class ConcreteSubjectA implements SubjectA{
@Override
public Boolean proxyMethod1(String s) {
// 业务逻辑代码
return true;
} @Override
public String proxyMethod2(String s) {
String res = s + "Call SubjectA proxy method2 success!";
return res;
}
} public class ConcreteSubjectB implements SubjectB{
@Override
public String proxyMethod1(String s) {
String res = s + "Call SubjectB proxy method1 success!";
return res;
}
}
构建请求处理程序,需要实现
InvocationHandler接口import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method; public class DynamicProxyHandler implements InvocationHandler{
// object: 需要动态创建的真实主题对象
private Object object; public DynamicProxyHandler() {} public DynamicProxyHandler(Object object) {
this.object = object;
} /**
* 实现 InvocationHandler 的 invoke() 方法
* @param proxy: 代理对象
* @param method: 代理方法
* @param args: 代理方法参数列表
*/
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
beforeInvoke(); 调用真实主题中定义的方法
Object res = method.invoke(object, args); afterInvoke();
return res;
} // 织入一些调用前和调用后的处理逻辑, 可以为客户端提供额外的服务
public void beforeInvoke() {
// 真实主题代理方法调用前
// 逻辑代码
} public void afterInvoke() {
// 真实主题代理方法调用后
// 逻辑代码
}
}
客户端调用
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Proxy; public class Client {
public static void main(String[] args) {
InvocationHandler invocationHandler = null; SubjectA subjectA = new ConcreteSubjectA();
SubjectB subjectB = new ConcreteSubjectB(); // 创建请求转发到的处理程序
invocationHandler = new DynamicProxyHandler(subjectA);
SubjectA proxyA = null; /**
* 通过反射创建代理类实例对象
* @param loader: 代理类的加载器
* @param interfaces: 代理类所实现的接口列表
* @param handler: 客户端请求转发到的处理程序
*/
proxyA = (SubjectA)Proxy.newProxyInstance(SubjectA.class.getClassLoader(), new Class[]{SubjectA.class}, invocationHandler);
String res = proxyA.proxyMethod2("Hi ");
System.out.println(res); invocationHandler = new DynamicProxyHandler(subjectB);
SubjectB proxyB = null;
proxyB = (SubjectB)Proxy.newProxyInstance(SubjectB.class.getClassLoader(), new Class[]{SubjectB.class}, invocationHandler);
res = proxyB.proxyMethod1("Hi ");
System.out.println(res);
}
}
15.5 代理模式优/缺点
代理模式使用场景:Java RMI (远程代理), Spring AOP(动态代理)
代理模式的优点主要如下:
- 客户端可以针对抽象层编程,增加和更换代理类不需要修改原代码,符合开闭原则
- 远程代理为位于不同地址空间对象的访问提供实现机制,将耗时耗资源的操作移至性能更好的远程主机,提高系统的运行效率
- 动态代理让系统根据需求动态创建代理类,且可以让同一个代理类代理多种不同的方法,相较于静态代理,显著降低了系统中类的个数
代理模式的缺点主要如下:
- 一些代理模式可能会需要复杂的实现过程,如远程代理
- 一些代理模式可能会造成请求的处理速度变慢,如保护代理
Java设计模式 —— 代理模式的更多相关文章
- Java设计模式-代理模式之动态代理(附源代码分析)
Java设计模式-代理模式之动态代理(附源代码分析) 动态代理概念及类图 上一篇中介绍了静态代理,动态代理跟静态代理一个最大的差别就是:动态代理是在执行时刻动态的创建出代理类及其对象. 上篇中的静态代 ...
- JAVA 设计模式 代理模式
用途 代理模式 (Proxy) 为其他对象提供一种代理以控制对这个对象的访问. 代理模式是一种结构型模式. 结构
- Java设计模式の代理模式
目录 代理模式 1.1.静态代理 1.2.动态代理 1.3.Cglib代理 代理模式 代理(Proxy)是一种设计模式,提供了对目标对象另外的访问方式;即通过代理对象访问目标对象.这样做的好处是 ...
- Java设计模式 - 代理模式
1.什么是代理模式: 为另一个对象提供一个替身或占位符以访问这个对象. 2.代理模式有什么好处: (1)延迟加载 当你需要从网络上面查看一张很大的图片时,你可以使用代理模式先查看它的缩略图看是否是自己 ...
- Java设计模式—代理模式
代理模式(Proxy Pattern)也叫做委托模式,是一个使用率非常高的模式. 定义如下: 为其他对象提供一种代理以控制对这个对象的访问. 个人理解: 代理模式将原类进行封装, ...
- Java设计模式——代理模式实现及原理
简介 Java编程的目标是实现现实不能完成的,优化现实能够完成的,是一种虚拟技术.生活中的方方面面都可以虚拟到代码中.代理模式所讲的就是现实生活中的这么一个概念:中介. 代理模式的定义:给某一个对象提 ...
- Java设计模式-代理模式(Proxy)
其实每个模式名称就表明了该模式的作用,代理模式就是多一个代理类出来,替原对象进行一些操作,比如我们在租房子的时候回去找中介,为什么呢?因为你对该地区房屋的信息掌握的不够全面,希望找一个更熟悉的人去帮你 ...
- Java设计模式--代理模式+动态代理+CGLib代理
静态代理 抽象主题角色:声明真实主题和代理主题的共同接口. 代理主题角色:代理主题内部含有对真实主题的引用,从而在任何时候操作真实主题对象:代理主题提供一个与真实主题相同的接口,以便在任何时候都可以代 ...
- Java设计模式——代理模式
public interface People { public void work(); } public class RealPeople implements People { public v ...
- Java 之 设计模式——代理模式
设计模式——代理模式 一.概述 1.代理模式 (1)真实对象:被代理的对象 (2)代理对象:代理真实对象的 (3)代理模式:代理对象代理真实对象,达到增强真实对象功能的目的 二.实现方式 1.静态代理 ...
随机推荐
- FII-PRX100-D开发板FPGA的烧录和RISC-V 软件代码下载
1. 生成*.bit文件之前先RESET结果 首先,打开Vivado FII_RISCV_V2.01工程(这里以V2.01版本为例),如图1所示. 图1 FII_RISCV_V2.01工程 要生成相应 ...
- Javaheima13
Java Stream流 salary 薪水 bonus 奖金 top performer 优秀员工 punish 处罚 1员工信息至少包含了(名称.性别.工资.奖金.处罚记录) 2开发一部有4个员工 ...
- PHP中获取时间的下一周下个月的方法
PHP中获取时间的下一周,下个月等通常用于定制服务的时候使用,比如包月会员,包年等等 //通常用于定制服务的时候使用,比如包月会员,包年等等 //获取当前时间过一个月的时间,以DATETIME格式显示 ...
- IO在指定目录建文件
path= "d:\\Project\\log\\log.txt"; File file = new File(path); //创建文件目录 if(!file.getParent ...
- python求列表中n个最大或最小的值
import heapq #y为结果列表,n为所求的n个值,x为来源列表 y=heapq.nsmallest(n,x) y=heapq.nlargest(n,x)
- Vue 的下拉刷新指令
loadmore: { //自定义指令: 下拉加载 bind(el, binding) { let p = 0; let t = 0; let down = true; el.addEventList ...
- 手写一个简易的ajax
function ajax(url,successFul){ const xhr=new XMLHttpRequest() xhr.open("Get",url,true) xhr ...
- Python项目案例开发从入门到实战-1.5Python文件的使用
Python对文件的操作通常按照三个步骤进行: un 使用open()函数打开(或建立)文件,并返回一个file对象. deux 使用file对象的读写方法对文件进行读写操作. trois 使用fil ...
- 文件上传 upload-labs Pass 12-16
Pass12 GET00%截断 审计源码 $is_upload = false; $msg = null; if(isset($_POST['submit'])){ $ext_arr = array( ...
- 文件的上传&预览&下载学习(三)
0.参考博客 https://www.pianshen.com/article/18961690151/ (逻辑流程图讲得很清楚) https://www.cnblogs.com/xiahj/p/vu ...