RPC.02-RMI

RMI

@Ref: https://ketao1989.github.io/2016/12/10/2016-12-10-rpc-theory-in-action/

RMI,全称是Remote Method Invocation,也就是远程方法调用。在JDK 1.2的时候引入到Java体系。

A typical implementation model of Java-RMI using stub and skeleton objects.

下面先看看RMI的调用流程:
../_images/2022/20220314231644.png

有些概念需要说明:

  • stub(桩):stub实际上就是在客户端上面的一个proxy。当我们的客户端代码调用API接口提供的方法的时候,RMI生成的stub代码块会将请求数据序列化,交给远程服务端处理,然后将结果反序列化之后返回给客户端的代码。这些处理过程,对于客户端来说,基本是透明无感知的。
  • remote:这层就是底层网络处理了,RMI对用户来说,屏蔽了这层细节。stub通过remote来和远程服务端进行通信。
  • skeleton(骨架):和stub相似,skeleton则是服务端生成的一个代理proxy。当客户端通过stub发送请求到服务端,则交给skeleton来处理,其会根据指定的服务方法来反序列化请求,然后调用具体方法执行,最后将结果返回给客户端。
  • registry(服务发现):rmi服务,在服务端实现之后需要注册到rmi server上,然后客户端从指定的rmi地址上lookup服务,调用该服务对应的方法即可完成远程方法调用。registry是个很重要的功能,当服务端开发完服务之后,要对外暴露,如果没有服务注册,则客户端是无从调用的,即使服务端的服务就在那里。

RMI Example:

/**
* 接口必须继承RMI的Remote
*/
public interface RmiService extends Remote {

/**
* 必须有RemoteException,才是RMI方法
*/
String hello(String name) throws RemoteException;
}

/**
* UnicastRemoteObject会生成一个代理proxy
*/
public class RmiServiceImpl extends UnicastRemoteObject implements RmiService {

public RmiServiceImpl() throws RemoteException {
}

public String hello(String name) throws RemoteException {
return "Hello " + name;
}
}

/**
* 服务端server启动
*/
public class RmiServer {

public static void main(String[] args) {
try {
RmiService service = new RmiServiceImpl();
//在本地创建和暴露一个注册服务实例,端口为9999
LocateRegistry.createRegistry(9999);
//注册service服务到上面创建的注册实例上
Naming.rebind("rmi://127.0.0.1:9999/service1",service);
}catch (Exception e){
e.printStackTrace();
}
System.out.println("------------server start-----------------");
}
}


/**
* 客户端调用rmi服务
*/
public class RmiClient {
public static void main(String[] args) {
try {
// 根据注册的服务地址来查找服务,然后就可以调用API对应的方法了
RmiService service = (RmiService)Naming.lookup("rmi://localhost:9999/service1");
System.out.println(service.hello("RMI"));
}catch (Exception e){
e.printStackTrace();
}
}
}

@ref: