RMI概念
RMI系统提供跨JVM调用对象方法的机制。
RMI框架使用的接口、类与方法放在java.rmi包下。
RMI程序一般分为两部分,提供远程对象的Server与调用远程对象方法的Client,这种应用也被称为对象分布应用。
对象分布应用需要做以下工作:
定位远程对象、与远程对象沟通、加载对象的类定义
动态代码加载的优势
RMI可以跨JVM获取对象的类定义,这种机制扩展了程序的功能。
远程接口、对象、方法
远程对象:可以被跨JVM调用。
远程对象类:实现了远程接口的类。
远程接口:扩展了java.rmi.Remote接口,并且其中定义的每一个方法都会抛出一个java.rmi.RemoteException。
RMI的调用机制不是将远程对象跨JVM传输复制,而是获取一个远程对象的引用stub,这个引用相当于一个远程对象的代理。
Client通过调用传输到本地的stub调用方法,stub将远程方法的调用过程封装。
远程对象的方法中,只有定义在远程接口中的方法可以被调用。
编写rmi应用流程:
- 设计远程接口,并且设计接口方法涉及的参数与返回值类型。
- 设计远程对象。
- 设计客户端,进行远程调用方法。
运行rmi应用程序流程:
- server运行register
- server运行编写的server端程序
- client运行编写的client端程序
编写RMI Server
编写远程接口
public interface Compute extends Remote {
<T> T executeTask(Task<T> t) throws RemoteException;
}
ps:RMI远程调用方法时,传值使用的是序列化机制,如果方法参数是一个对象,此对象需要实现java.io.Serializiable接口。
ps:几乎一切类型的数据都可以作为远程接口返回值或参数。即,基础类型、远程对象、本地对象。远程接口中参数、返回值涉及到的对象,都是值传递,即在receiver中生成一个副本,sender中的对象的状态变化与receiver中副本对象状态的变化无关。
RMI Server主程序流程
- 创建install SecurityManager对象,用于对系统资源访问进行控制。
- 创建远程对象,获取远程对象引用stub
- 获取本地register的远程对象引用
- 设置远程对象引用的name,然后将其与远程对象引用一起bind进register
创建install ScurityMnager对象
if(System.getSecurityManager() == null) {
System.setSecurityManager(new SecurityManager());
}
创建一个远程对象,并且获取其远程对象引用stub
Compute engine = new ComputeEngine();
Compute stub = (Compute)UnicastRemoteObject.exportObject(engine, 0);
ps:stub是一个远程接口类型的代理对象。静态方法的第二个参数用于设置接收方法调用请求的TCP端口,将其设置为0时,表示使用匿名端口,即端口在运行时由RMI与操作系统共同决定。
ps:exportObject方法声明会抛出一个RemoteException,此异常为checked异常,所以需要处理。
获取本地主机的register远程对象
Registry registry = LocateRegistry.getRegistry();
note:获取本地主机的register的远程对象。
ps:registry远程对象用于设置其他的远程对象,此远程对象在使用getRegistry()方法不传参获得时,默认使用1099作为端口。
ps:registry远程对象用于使用name字符串查找其他远程对象。
将远程对象设置进registry
registry.rebind(name, stub);
note:将远程对象stub与字符串name绑定。
ps:绑定进register中的引用,可以通过name直接获取。
ps:设置后之后,不需要再设置一个线程用于等待请求,可以直接结束代码,此时远程对象不会被GC处理掉,而是会等待远程Client调用。
编写RMI Client
RMI Client主程序流程
- 创建install SecurityManager对象
- 获取远程主机的register的远程对象引用
- 利用register获取远程对象引用stub
- 通过stub操作远程对象
获取指定主机的register远程对象
Registry registry = LocateRegistry.getRegistry(host);
note:通过host与默认端口1099获取指定register远程对象。
通过register获取远程对象
Compute compute = (Compute) registry.lookup(name);
运行RMI分布式应用
运行register
start rmiregistry
ps:运行在server端
运行server端
java -cp D:\DevelopmentSpace\compute.jar -Djava.rmi.server.codebase=file:/D:/DevelopmentSpace/compute.jar -Djava.rmi.server.hostname=mycomputer.example.com -Djava.security.policy=server.policy engine.ComputeEngine
note:运行engine.ComputeEngine
ps:codebase设置client端获取服务器class文件的url路劲,policy设置安全策略文件
运行客户端
java -cp D:\DevelopmentSpace\compute.jar -Djava.rmi.server.codebase=file:/D:/DevelopmentSpace/compute.jar -Djava.security.policy=server.policy client.ComputePi
note:运行client.ComputePi
详细教程:https://docs.oracle.com/javase/tutorial/rmi/overview.html