设计模式(11)代理模式The Proxy Pattern - 1 - 远程代理rmi
代理模式
假设现在需要设置一个监视器Monitor,能够监视糖贩卖机GumballMachine的状态,位置信息、还有多少糖果等。一个简单的想法就是创建一个Monitor的类,构造参数包括GumballMachine。然后就可以调用GumballMachine的一些状态函数。
但是如果GumballMachine在另一台机器上、或者在不同的Java堆上,显然是不能够将GumballMachine的引用传递过来。
这是后就需要使用代理模式来解决。
思路:添加一个新的类叫做MonitorProxy。Monitor和MonitorProxy在一个Java堆上,MonitorProxy这个代理负责与远程的GumballMachine进行沟通,得到数据后把自己伪装成GumballMachine来被MonitorProxy调用。
远程方法
原理
我们要这设计这样一个系统:该系统允许我们调用本地的一个对象,本地的这个对象又能够将请求转发到远程对象上。
四个关键的角色 client 、client helper、service helper、Service
客户端
client helper的作用是让client调用和调用远程remoter效果一样。client helper处理转发了client的请求。
换句话说,从client的角度来看,client就是在调用一个远程的服务。client helper假装自己是service
client helper有和service一样的方法。但是他们的逻辑不同,client helper里面的方法是对service进行响应请求、然后进行参数转换返回给client的。
服务器端
同客户端一样,存在一个Service helper负责处理对话(可能是Socket)
Java RMI(Remote Method Invocation)
Java RMI已经封装好了相关功能。不需要自己动手写网络和I/O相关的代码了。和调用本地的对象一样。唯一的区别时会有网络通讯,可能引起失败抛出异常。
client helper 叫做RMI Stub
service helper 叫做RMI Skeleton
使用RMI
Remote service
一共五步走:
1. 写一个Remote 接口
这个远程接口所定义的方法是client远程调用的。这也就意味着stub和实际的service都要实现这个接口
//1. 扩展java.rmi.Remote接口
public interface MyRemote extends Remote{//2. 接口中所有的函数都要能够抛出RemoteException异常//因为涉及到网络或者I/O,可能出现连接错误等。public String sayHello() throws RemoteException;//3. 要保证参数和返回值都是基本的数据类型或者是可序列化的。
}
2. 实现Remote接口
远程的class要实现上一步定义的接口
// 1. 注意MyRemoteImpl所继承的类UnicastRemoteObject, 这个类定义了一些远程服务所需要的功能函数。
public class MyRemoteImpl extends UnicastRemoteObject implements MyRemote{// 2. 抛出这个异常的原因是它的父类可能UnicastRemoteObject会抛出这个异常,所以子类也一样。public MyRemoteImpl() throws RemoteException{}public String sayHello() {return "server says, hi";// other impl}// 主函数入口。方便起见直接写在了这个类public static void main (String[] args) {/*方法一*/// 需要运行第四步命令try {MyRemote service = new MyRemoteImpl();Naming.rebind(“RemoteHello”, service); //在RMI中注册} catch(Exception ex) {ex.printStackTrace();}}/*方法二*///使用内在注册器,不用单独运行rmiregistry服务。try {//默认端口1099Registry registry = LocateRegistry.createRegistry(1099);MyRemoteImpl service = new MyRemoteImpl();registry.bind("RemoteHello", service); // 在RMI中注册System.out.println("Run Successfully");} catch (Exception ex) {ex.printStackTrace();}
}
定义好service,需要使用。方法就是把上面的MyRemoteImpl实例化之后,在RMI 中注册这个服务。
try{
MyRemote service = new MyRemoteImpl();
Naming.rebind(“RemoteHello”, service); //起一个名字并且注册。
}catch(Exception ex){
…
}
3. 生成stubs和skeletons(即service helper和client helper)(java1.5及以后不再被需要)可以略过。
使用rmic工具生成两个类:
rmic MyRemoteImpl
- MyRemoteImpl_Stub.class 给client
- MyRemoteImpl_Skel.class 给service
4. 运行RMI registry(在service主机上)
rmiregistry
确保运行的文件能够到达你的类。稳妥的办法是从你的类文件运行此命令。
例如从全限定类名的根目录开始。比如bin/test/MyRemoteImpl.class
那么从bin目录运行
5. 运行远程服务(在service主机上)
java MyRemoteImpl
xxxx是main函数的远程服务。
从全限定类名的根目录开始。同上。
Client
client如何能够得到stub object呢?
import java.rmi.*;
public class MyRemoteClient {// 主程序入口public static void main (String[] args) {new MyRemoteClient().go();}public void go() {try {//查找,返回时Object,需要Cast//如果是默认端口和本地地址,可以忽略不写MyRemote service = (MyRemote) Naming.lookup(“rmi://127.0.0.1:1099/RemoteHello”);String s = service.sayHello();System.out.println(s);} catch(Exception ex) {ex.printStackTrace();}}
}
- client去rmi注册表中查找RemoteHello(是注册时的名字)
- Client需要有远程的接口MyRemote.java
client如何获得stub这个类?
- 方法一:手工交付
- 方法二:动态下载。放到服务器上动态,如果本地搜索不到就是用http请求下来。
注意事项
- 在远程服务启动之前,启动rmiregistry。service运行时调用了Naming.rebind(),这个需要rmiregistry服务。所以必须提前运行
- 忘记使参数或者返回类型序列化。这个编译器检查不出来。只有运行时报错。
- 忘记把stub给client。
代理模式定义
为另一个对象提供一个代理或者占位符,来控制对他的访问。
几个控制访问的方法:
一个远程代理控制对远程对象的访问
虚拟代理控制对创建成本较高的资源的访问
保护代理控制对于权限资源的访问
远程代理
上面提的那种
虚拟代理
虚拟代理用来标识一个需要昂贵代价去创建的对象。虚拟代理通常来推迟这个对象的创建,直到这个对象被需要时再创建。在被代理对象创建完成之前,虚拟代理扮演者被代理者(RealSubject)的角色, 创建完成之后,虚拟代理把请求转交给被代理对象。
例如:播放在线音乐,当音乐封面没有被下载的时候,虚拟代理充当封面的角色(可以使一串字符串“正在下载封面”,或者其他的某个默认图片), 一旦封面下载完成,虚拟代理就把所有调用的方法委托给实际的图片。
// Head Fist Design Pattern P456
class ImageProxy implements Icon {ImageIcon imageIcon;URL imageURL;Thread retrievalThread;boolean retrieving = false;public ImageProxy(URL url) { imageURL = url; }public int getIconWidth() {if (imageIcon != null) {return imageIcon.getIconWidth();} else {return 800;}}public int getIconHeight() {if (imageIcon != null) {return imageIcon.getIconHeight();} else {return 600;}}public void paintIcon(final Component c, Graphics g, int x, int y) {if (imageIcon != null) {imageIcon.paintIcon(c, g, x, y);} else {g.drawString(“Loading CD cover, please wait...”, x+300, y+190);if (!retrieving) {retrieving = true;retrievalThread = new Thread(new Runnable() {public void run() {try {imageIcon = new ImageIcon(imageURL, “CD Cover”);c.repaint();} catch (Exception e) {e.printStackTrace();}}});retrievalThread.start();}}}
}
设计模式(11)代理模式The Proxy Pattern - 1 - 远程代理rmi相关推荐
- Android常见设计模式——代理模式(Proxy Pattern)(二)
文章目录 1. 前言 2. 远程代理(Remote Proxy) 3. 后记 1. 前言 在上篇Android常见设计模式--代理模式(Proxy Pattern)中基本上知道了什么是代理模式,以及对 ...
- Android常见设计模式——代理模式(Proxy Pattern)
文章目录 1. 前言 2. 代理模式(Proxy Pattern) 2.1 静态代理模式 2.2 动态代理模式 3. Android 中的代理模式 3.1 Retrofit中的代理模式(没有被代理者) ...
- Net设计模式实例之代理模式(Proxy Pattern)
一.代理模式简介(Brief Introduction) 代理模式(Proxy Pattern)对其他对象提供一种代理以控制对这个对象的访问. 二.解决的问题(What To Solve) 1.远程代 ...
- 【java项目实战】代理模式(Proxy Pattern),静态代理 VS 动态代理
这篇博文,我们主要以类图和代码的形式来对照学习一下静态代理和动态代理.重点解析各自的优缺点. 定义 代理模式(Proxy Pattern)是对象的结构型模式,代理模式给某一个对象提供了一个代理对象,并 ...
- C#设计模式之十二代理模式(Proxy Pattern)【结构型】
一.引言 今天我们要讲[结构型]设计模式的第七个模式,也是"结构型"设计模式中的最后一个模式,该模式是[代理模式],英文名称是:Proxy Pattern.还是老套路,先从名字上来 ...
- 设计模式笔记15:代理模式(Proxy Pattern)
一.代理模式的内容 代理模式为另一个对象提供一个替身或占位符以访问这个对象. 给某一个对象提供一个代理,并由代理对象控制对原对象的引用.代理模式的英文叫做Proxy或Su ...
- 代理对象我所理解的设计模式(C++实现)——代理模式(Proxy Pattern)
文章结束给大家来个程序员笑话:[M] 概述 作为C++工程师,免不了要管理内存,内存管理也是C++中的难点,而智能指针采用引用计数的方法很方便的帮我们管理了内存的应用,极大方便了我们的任务效率.而智能 ...
- C#设计模式(13)——代理模式(Proxy Pattern)
一.引言 在软件开发过程中,有些对象有时候会由于网络或其他的障碍,以至于不能够或者不能直接访问到这些对象,如果直接访问对象给系统带来不必要的复杂性,这时候可以在客户端和目标对象之间增加一层中间层,让代 ...
- 设计模式笔记——代理模式(Proxy Pattern)
一.引言 在软件开发过程中,有些对象有时候会由于网络或其他的障碍,以至于不能够或者不能直接访问到这些对象,如果直接访问对象给系统带来不必要的复杂性,这时候可以在客户端和目标对象之间增加一层中间层,让代 ...
最新文章
- WPF 中动态创建和删除控件
- 由mysql分区想到的分表分库的方案
- BugkuCTF-Misc:做个游戏(08067CTF)
- Console的使用——Google Chrome代码调试
- 【渝粤教育】广东开放大学 网络整合营销 形成性考核 (53)
- 探测活动主机的代码linux,Linux入侵痕迹检测方案【华为云技术分享】
- 关于“100g文件全是数组,取最大的100个数”解决方法汇总
- ai 自动外呼 微信加好友_制作一个可爱的Pwnagotchi AI好友来自动审核Wi-Fi网络
- 易中天:望子成人,而非望子成龙
- MQX4.0:MK60DZ10.h头文件GPIO模块…
- 【智能手环APP for Android 】01 百度地图展示行动轨迹
- c语言对数组取反,C语言中按逆取反是什么意思
- 自由 Freedom
- pikachu之xss漏洞学习
- 7-86 小明的晚饭 (50分)
- python编写我的世界
- brew Error: Cask ‘adoptopenjdk8‘ is unreadable
- 恩科迪亚Encodya for mac(单机游戏)
- 【Simulink教程案例4】使用Simulink自带的模块实现PID控制器,并对比案例1的PID控制器
- 51Nod - 1588 幸运树(DFS)