RMI(Remote Method Interface)远程方法调用与 RPC(Remote Procedure Call)远程过程调用有什么区别呢?

1. 什么是 RMI?

RMI,远程方法调用(Remote Method Invocation)是 Enterprise JavaBeans 的支柱,是建立分布式 Java 应用程序的方便途径。RMI 是非常容易使用的,但是它非常的强大。

与 RPC 类似,RMI 的基础也是是接口,RMI 构架基于一个重要的原理:定义接口和定义接口的具体实现是分开的。下面我们通过具体的例子,建立一个简单的远程服务和使用它的客户程序。

我们需要按照以下步骤来进行程序的构建:

  1. 定义 Remote 接口。
  2. 在 Provider 端实现 Remote 接口。
  3. 实现客户端 。
  4. Provider 端将实现 Remote 接口的对象注册到 JVM 的 Registry。
  5. 生成 Stub 对象(Java 1.5 之后不必显式实现,动态代理已经做好了)。
  6. 运行 Registry,一个类似于路由的东西。
  7. 运行服务端。
  8. 运行客户端。

与上一节讲的 RPC 类似,首先也要声明一个远程接口,区别在于这个接口需要继承 Remote 接口,且里面生命的方法必须 throws RemoteException。

API接口

1
2
3
public interface HelloService extends Remote{
	String sayHello(String name) throws RemoteException;
}

同样的,Provider 服务端。别忘了继承 UnicastRemoteObject 。当调用 sayHello 方法时会将该对象的 hashCode 值打印在控制台上。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
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 服务端的启动代码

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
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 端:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
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 的特点对比:

  1. RMI 获取到的是远程对象的引用而 RPC 是远程对象的副本。

  2. 方法调用方式不同:

    RMI 中是通过在客户端的 Stub 对象作为远程接口进行远程方法的调用。每个远程方法都具有方法签名。如果一个方法在服务器上执行,但是没有相匹配的签名被添加到这个远程接口 (Stub) 上,那么这个新方法就不能被 RMI 客户方所调用。

    RPC 中是通过网络服务协议向远程主机发送请求,请求包含了一个参数集和一个文本值,通常形成“ classname.methodname (参数集) ”的形式。RPC 远程主机就去搜索与之相匹配的类和方法,找到后就执行方法并把结果编码,通过网络协议发回。

  3. 适用语言范围不同:

    RMI 只用于 Java。

    RPC 是网络服务协议,与操作系统和语言无关。