一、入门篇
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工作原理