RMI 与 RPC ——深入理解 RPC 远程调用(二)
RMI(Remote Method Interface)远程方法调用与 RPC(Remote Procedure Call)远程过程调用有什么区别呢?
1. 什么是 RMI?
RMI,远程方法调用(Remote Method Invocation)是 Enterprise JavaBeans 的支柱,是建立分布式 Java 应用程序的方便途径。RMI 是非常容易使用的,但是它非常的强大。
与 RPC 类似,RMI 的基础也是是接口,RMI 构架基于一个重要的原理:定义接口和定义接口的具体实现是分开的。下面我们通过具体的例子,建立一个简单的远程服务和使用它的客户程序。
我们需要按照以下步骤来进行程序的构建:
- 定义 Remote 接口。
- 在 Provider 端实现 Remote 接口。
- 实现客户端 。
- Provider 端将实现 Remote 接口的对象注册到 JVM 的 Registry。
- 生成 Stub 对象(Java 1.5 之后不必显式实现,动态代理已经做好了)。
- 运行 Registry,一个类似于路由的东西。
- 运行服务端。
- 运行客户端。
与上一节讲的 RPC 类似,首先也要声明一个远程接口,区别在于这个接口需要继承 Remote 接口,且里面生命的方法必须 throws RemoteException。
API接口
public interface HelloService extends Remote{
String sayHello(String name) throws RemoteException;
}
同样的,Provider 服务端。别忘了继承 UnicastRemoteObject 。当调用 sayHello 方法时会将该对象的 hashCode 值打印在控制台上。
public class RmiHelloServiceImpl extends UnicastRemoteObject implements HelloService {
public RmiHelloServiceImpl() throws RemoteException {
super();
}
private static final long serialVersionUID = 2L;
@Override
public String sayHello(String name) throws RemoteException{
System.out.println("hashCode:"+hashCode());
return "Hello " + name;
}
}
Provider 服务端的启动代码
public class RmiServer {
public static void main(String[] args) {
try {
RmiHelloServiceImpl impl = new RmiHelloServiceImpl();
LocateRegistry.createRegistry(1099);
Naming.rebind("rmi://localhost:1099/rmitest", impl);
System.out.println("RMI Server 启动完毕...");
} catch (RemoteException e) {
e.printStackTrace();
} catch (MalformedURLException e) {
e.printStackTrace();
}
}
}
Client 端:
public class RmiClient {
public static void main(String[] args) {
try {
HelloService helloService = (HelloService) Naming.lookup("rmi://localhost:1099/rmitest");
System.out.println("hashCode:"+hashCode());
String sayHello = helloService.sayHello("rmi");
} catch (MalformedURLException | RemoteException | NotBoundException e) {
e.printStackTrace();
}
}
}
Ok,依次执行两个程序,可以看到在控制台上打印的两个 hashCode 值是一样的。
我们来改造一下上一节中的例子,在接口上也给他加上打印 hashCode 的代码,却发现两次打印的 hashCode 值不同。
这就引出了 RPC 和 RMI 最重要的一点区别,RMI 获取到的是远程对象的引用而 RPC 是远程对象的副本。
来总结一下 RMI 与 RPC 的特点对比:
-
RMI 获取到的是远程对象的引用而 RPC 是远程对象的副本。
-
方法调用方式不同:
RMI 中是通过在客户端的 Stub 对象作为远程接口进行远程方法的调用。每个远程方法都具有方法签名。如果一个方法在服务器上执行,但是没有相匹配的签名被添加到这个远程接口 (Stub) 上,那么这个新方法就不能被 RMI 客户方所调用。
RPC 中是通过网络服务协议向远程主机发送请求,请求包含了一个参数集和一个文本值,通常形成“ classname.methodname (参数集) ”的形式。RPC 远程主机就去搜索与之相匹配的类和方法,找到后就执行方法并把结果编码,通过网络协议发回。
-
适用语言范围不同:
RMI 只用于 Java。
RPC 是网络服务协议,与操作系统和语言无关。