什么是RPC
什么是RMI
- Remote Method Invocation
本地jvm调用率远程的jvm上的方法,但在客户端这边感觉的就像在调用本地方法一样
RMI框架使用过程
- 制作远程服务接口
需要继承Remote,类里的远程方法需要throws RemoteException
,让客户了解到这有可能会调用失败 - 实现远程服务,实现刚刚的远程接口,需要扩展UnicastRemoteObject,使用它的超类来完成一些工作,使自己变成一个远程对象,
- 产生stub和skeleton
命令行rmic为服务类产生stub和skeleton - 命令行开启remiregistry
- 启动服务
实例化服务对象,到rmi注册机上注册
RMI的使用实例
- RemoteServiceInterface
import java.rmi.Remote;
import java.rmi.RemoteException;
/**
* 定义远程服务接口
* Created by liqiushi on 2017/12/19.
*/
public interface RemoteServiceInterface extends Remote{
String getString() throws RemoteException;
void setString(String string)throws RemoteException;
void inputStr() throws RemoteException;
}
- RemoteService
import java.rmi.RemoteException;
import java.rmi.server.UnicastRemoteObject;
/**
* Created by liqiushi on 2017/12/19.
*/
public class RemoteService extends UnicastRemoteObject implements RemoteServiceInterface {
private String string;
//超类
public RemoteService(String string) throws RemoteException {
super();
this.string = string;
}
@Override
public String getString()throws RemoteException {
return string;
}
@Override
public void setString(String string)throws RemoteException {
this.string = string;
}
@Override
public void inputStr() throws RemoteException {
System.out.println(string);
}
}
- ServerRunner
import java.net.MalformedURLException;
import java.rmi.Naming;
import java.rmi.RemoteException;
import java.rmi.registry.LocateRegistry;
/**
* 远程服务server
* Created by liqiushi on 2017/12/19.
*/
public class ServerRunner {
public static void main(String[] args) {
try {
//server 本地JVM创建一个RMI注册表
LocateRegistry.createRegistry(8001);
//创建一个远程服务
RemoteServiceInterface remoteService = new RemoteService("local rmi test!");
//注册到rmi注册机上
Naming.rebind("rmi://127.0.0.1:8001/inputStr",remoteService);
} catch (RemoteException e) {
e.printStackTrace();
} catch (MalformedURLException e) {
e.printStackTrace();
}
}
}
- ClientRunner
import java.net.MalformedURLException;
import java.rmi.Naming;
import java.rmi.NotBoundException;
import java.rmi.RemoteException;
/**
* Created by liqiushi on 2017/12/19.
*/
public class ClientRunner {
public static void main(String[] args) {
//在rmi注册机上找到远程stub server代理对象
try {
RemoteServiceInterface remoteService = (RemoteServiceInterface) Naming.lookup("rmi://127.0.0.1:8001/inputStr");
remoteService.inputStr();
remoteService.setString("client modify!");
remoteService.inputStr();
} catch (NotBoundException e) {
e.printStackTrace();
} catch (MalformedURLException e) {
e.printStackTrace();
} catch (RemoteException e) {
e.printStackTrace();
}
}
}
上述代码注意
- 是产生了一个本地的rmi注册机
LocateRegistry.createRegistry(8001);
,服务和rmi注册机是同一个jvm,在jdk1.5后,不再需要手动生成stub和skeleton - RemoteService构造函数需要抛出超类的
RemoteException
什么是stub
stub
每个远程对象都包含一个代理对象stub,当运行在本地Java虚拟机上的程序调用运行在远程Java虚拟机上的对象方法时,它首先在本地创建该对象的代理对象stub, 然后调用代理对象上匹配的方法,代理对象会作如下工作:
与远程对象所在的虚拟机建立连接
打包(marshal)参数并发送到远程虚拟机
等待执行结果
解包(unmarshal)返回值或返回的错误
返回调用结果给调用程序
stub 对象负责调用参数和返回值的流化(serialization)、打包解包,以及网络层的通讯过程。
skeleton
每一个远程对象同时也包含一个skeleton对象,skeleton运行在远程对象所在的虚拟机上,接受来自stub对象的调用。当skeleton接收到来自stub对象的调用请求后,skeleton会作如下工作:
解包stub传来的参数
调用远程对象匹配的方法
打包返回值或错误发送给stub对象
远程对象的stub和skeleton对象都是由rmic编译工具产生的。