设计模式
控制对象的访问
远程方法调用RMI
graph LR
A((客户对象))
B((客户辅助对象))
C((服务对象))
D((服务辅助对象))
A --> B
B --> A
C --> D
D --> C
B --> D
D --> B
RMI是java内置的一个构架远程调用方法的工具
- RMI Stub:这个其实就是客户辅助对象
- RMI Skeleton:这个就是是服务辅助对象
制作远程服务
五个步骤:
- 制作远程接口:定义要供客户调用的远程方法
- 制作远程实现:实现接口文件中定义的方法
- 利用rmic产生stub和skeleton:RMI内置的服务,可以帮助自动生成RMI Stub和RMI Skeleton。
- 启动RMI registry:在客户终端运行,用于查找代理的位置,也就是RMI Stub,用于和RMI Skeleton联系。
- 开始远程服务:服务端运提供可调用的服务。
Java制作远程接口
// 定义远程服务接口
public interface MyRemote extends Remote {
// 定义一个简单的方法,其中的返回类型必须是原语(primitive)或者可序列化(Serializable)的类型,因为返回值需要打包在网络中传输。
public String sayHello() throws RemoteException;
}
//
Java制作远程实现
// 需要成为远程对象,直接继承UnicastRemoteObject,帮你都写好了
public class MyRemoteImpl extends UnicastRemoteObject implements MyRemote {
public MyRemoteImpl() throws RemoteException {}
@override
public String sayHello() throws RemoteException {
return "Hello"
}
}
除此之外,我们还需要一个入口来启动MyRemoteImpl,并完成注册。
public static void main (String[] args) {
try {
// 实例化服务
MyRemote service = new MyRemoteImpl();
// 为实例化后的服务命名,方便注册到registry中去。
Naming.rebind("RemoteHello", service)
} catch(Exception ex) {
......
}
}
产生Stub和Skeleton
这里是直接使用rmic工具自动生成的
%rmic MyRemoteImpl
执行remiregistry
启动终端
%rmiregistry
启动服务
%java MyRemoteImpl
stub具体是怎么寻找到服务的
MyRemote service = (MyRemote) Naming.lookup("rmi://127.0.0.1/RemoteHello")
其实本质上就是服务端启动服务,RMI Registry监听端口。而后客户端通过lookup去服务端的RMI Registry出查询特定的服务对象。服务端通过接收到的请求定位到本地上注册的具体服务,然后将服务对应的对象序列化后发送给客户端的Stub,而后客户端反序列化后,将其存储下来(这样客户端才能知道里面有哪些方法)。之后客户端就直接和存在Stub里的远程代理对象交互了,而代理对象会自己处理网络层面的异地交互。
而请求端其实就是注册了服务端的监听的地址,以及服务端注册的服务的名字,然后通过这几个信息去调用远程的服务。
定义代理模式
代理模式为另一个对象提供一个替身或者占位符以控制对这个对象的访问。
classDiagram
class Subject
<<interface>> Subject
Subject: request()
class Proxy
Proxy: request()
class RealSubject
RealSubject: request()
Proxy ..|> Subject
RealSubject ..|> Subject
Proxy --> RealSubject : contains
Proxy和RealSubject都是Subject的实现,这样的目的是在使用Proxy代替RealSubject提供访问的时候不会出错。同时Proxy也包含有对RealSubject的访问,这样Proxy就可以在外部请求到来的时候,对ReaalSubject进行调用了。有的时候Proxy还会控制RealSubject的创建。 除了远程代理,代理模式还可以用于
- 虚拟代理控制访问创建开销大的资源
- 保护代理基于权限控制对资源的访问