首页 > 代码库 > RMI - Java远程方法调用

RMI - Java远程方法调用

一、入门篇

Java RMI指的是远程方法调用(Remote Method Invocation). 它是一种机制, 能够让不同操作系统之间程序实现方法调用. 

比如: 一台电脑上的Java程序可以通过RMI调用另一台电脑上的方法(EJB底层就是使用RMI).


二、RMI和webservice

RMI是在TCP协议上传递可序列化的Java对象, 只能用在Java虚拟机上, 客户端和服务端必须都是Java.

webservice是在http协议上传递xml文件, 它与语言和平台无关, 可以在异构系统间传递.

对于不同语言间的通讯我们可以考虑用webservice或者公用对象请求代理体系COBRA来实现.


三、RMI的优点

RMI为分布式系统设计、编程带来了遍历. 只要按照RMI规则设计程序, 就不必过问网络细节, 如: TCP, Socket等.

任意两台计算机之间的通讯完全由RMI负责, 调用远程计算机上的对象就像调用本地对象一样方便.


四、实例篇

我们编写这样一个小程序: 客户端传递两个数字给服务器端加法运算方法, 返回结果给客户端.

1. 定义一个远程接口类

/**
 * 定义一个远程接口
 * @author zhangjim
 */
public interface ISumService extends Remote { // 必须继承Remote接口
	
	// 需要远程调用的方法必须抛出RemoteException
	public int sum(int a, int b) throws RemoteException; 
	
}

远程接口必须要继承: java.rmi.Remote, 接口中的每一个方法必须抛出远程异常: java.rmi.RemoteException

为什么要抛出这个异常呢? 因为任何远程方法调用实际上要进行许多低级网络操作, 而网络错误可能在调用过程中随时发生.

因此, 所有RMI操作都应该放到try-catch块中.


2. 定义一个实现远程接口的类

/**
 * 远程接口的实现类
 * @author zhangjim
 */
public class SumServiceImpl extends UnicastRemoteObject implements ISumService { // 必须从UnicastRemoteObject继承 

	private static final long serialVersionUID = -3559316404683903070L;
	
	// 需要一个抛出Remote异常的默认初始化方法 
	SumServiceImpl() throws RemoteException { 
		
	}
	
	// 业务方法, 传入两个数字, 返回相加结果
	public int sum(int a, int b) throws RemoteException {
		return a + b;
	}
}
UnicastRemoteObject: 让客户机与服务器对象实例建立一对一的连接


3. 创建服务器, 用于启动RMI服务并绑定远程对象

public class Server {
	public static void main(String[] args) {
		try {
			// 创建一个远程对象 
			ISumService sumService = new SumServiceImpl();
			
			// 创建RMI注册表, 启动RMI服务, 并指定端口为8888(Java默认端口是1099)
			// 这一步必不可少, 缺少注册表创建,则无法绑定对象到远程注册表上 
			LocateRegistry.createRegistry(8888); 
			
			// 把远程对象注册到RMI注册服务器上,并命名为sum 
			// 绑定的URL标准格式为:rmi://host:port/name(其中协议名可以省略, 下面两种写法都是正确的)
			Naming.bind("rmi://localhost:8888/sum", sumService);
			// Naming.bind("//localhost:8888/sum", sumService);
			System.out.println("远程对象绑定成功!");
		} catch (Exception e) {
			throw new RuntimeException("出错了...", e);
		}
	}
}

也可以在命令行通过命令 rmiregistry 启动注册服务, 而且要事先用RMIC在bin目录编译SumServiceImpl类生成一个占位程序(stub类)为它所用


4. 创建客户端程序, 对RMI进行调用

/**
 * 客户端测试,在客户端调用远程对象上的远程方法,并返回结果
 * @author zhangjim
 */
public class Client {
	public static void main(String[] args) {
		try {
			// 在RMI服务注册表中查找名称为sum的对象
			ISumService sumService = (ISumService) Naming.lookup("rmi://localhost:8888/sum");
			
			// 调用相加方法
			System.out.println("相加结果为: " + sumService.sum(1, 2));
		} catch (Exception e) {
			throw new RuntimeException("出错了...", e);
		}
	}
}

五、RMI的文章

1. 理解RMI工作原理

2. Java RMI服务器框架