JAVA核心知识点--RMI

目录

创建远程服务

创建远程服务接口

实现远程服务接口

使用rmic产生stub和skeleton

启动RMI registry(执行rmiregistry) 

启动远程服务 

客户端如何取得stub对象?


参考书籍:《Head First Java (中文版)》第二版 

Java的远程方法调用 (Remote Method Invocation,RMI)技术,能够帮助我们实现:某一个Java虚拟机上的对象可以调用另一台计算机、另一个Java虚拟机上面的对象的方法,就像调用本地对象的方法一样。

使用RMI时,需要指定协议:JRMP(Java远程消息交换协议JRMP,Java Remote Messaging Protocol)或是IIOP(互联网内部对象请求代理协议,Internet Inter-ORB Protocol)。JRMP是RMI原生的协议,它是为了Java对Java间的远程调用而设计的。另一方面,IIOP是为了CORBA(Common Object Request Broker Architecture)而产生的,它让你能够调用Java对象或其它类型的远程方法。

RMI远程方法调用过程如下图所示: 

JAVA核心知识点--RMI_第1张图片

创建远程服务

创建远程服务包含以下5个步骤:

创建远程服务接口

远程的服务接口要继承java.rmi.Remote,用来定义客户端可以远程调用的方法,stub和skeleton都要实现此接口。它是个作为服务的多态化类,也就是说,客户端会调用实现此接口的stub,而此stub因为会执行网络和输入/输出工作,所以可能会发生各种问题,客户端必须处理或声明异常来认知这一类风险。并且,远程方法的参数和返回值必须都是primitive基本数据类型或Serializable的。 

package rmi;

import java.rmi.Remote;
import java.rmi.RemoteException;

/**
 * 远程服务接口
 */
public interface IRemoteService extends Remote {

	public String sayHello() throws RemoteException;
}

实现远程服务接口

这是真正执行的类,它实现了定义在远程服务接口中的方法,它是客户端会调用的对象。为了要成为远程服务对象,这个实现类必须要包含与远程有关的功能。其中最简单的方式就是继承java.rim.server.UnicastRemoteObject,以调用父类的远程功能来处理这些工作。UnicastRemoteObject有个小问题:它的构造函数会抛出RemoteException异常,因此需要为你的实现类声明一个构造函数,并在其中抛出RemoteException异常。 

package rmi;

import java.rmi.RemoteException;
import java.rmi.server.UnicastRemoteObject;

/**
 * 远程服务实现
 */
public class RemoteServiceImpl extends UnicastRemoteObject implements
		IRemoteService {

	// 无需声明RemoteException异常
	public String sayHello() {
		return "Server syas , 'Hey'";
	}

	// 父类的构造函数声明了异常,所以你也得在构造函数中声明异常
	public RemoteServiceImpl() throws RemoteException {

	}

}

注意:要记得当类被初始化的时候,父类的构造函数一定会被调用,如果父类的构造函数抛出异常,你也得声明你的构造函数会抛出异常。

使用rmic产生stub和skeleton

伴随Java Software Development Kit而来的rmic工具会以远程服务的实现类(不是远程服务接口)产生出两个新的类:stub和skeleton。它会按照命名规则在你的远程服务实现类名称后面加上_Stub或_Skel(JDK 1.2以后将只需要_Stub文件)。

执行rmic命令时需要考虑到包目录结构和完整名称,我的所有示例代码的.class文件均放置在D:\bin\rmi目录下,RemoteServiceImpl类的完整名称为rmi(包路径).RemoteServiceImpl。

JAVA核心知识点--RMI_第2张图片

由于未指定rmic的生成的目标文件的存放位置,所以会将生成的stub文件和skeleton文件放置在RemoteServiceImpl.class文件所在目录(D:\bin\rmi)下。  

JAVA核心知识点--RMI_第3张图片

启动RMI registry(执行rmiregistry) 

rmiregistry就像是电话簿,用户会从此处取得代理(客户端的stub对象),因此需要在远程服务启动前先启动RMI registry。 

JAVA核心知识点--RMI_第4张图片

启动远程服务 

远程服务实现类定义完成之后还需要使用java.rmi.Naming的bind()方法 来向RMI registry注册服务,当你注册对象时,RMI系统会把stub加到RMI registry中。 

package rmi;

import java.rmi.Naming;

public class Server {
	public static void main(String[] args) {
		try {
			// 创建出远程对象,然后使用静态的Naming.bind()来产生关联
			// 所注册的名称会供客户端查询
			IRemoteService service = new RemoteServiceImpl();
			Naming.bind("RemoteHello", service);
			//Naming.rebind("Remote Hello", service);
		} catch (Exception e) {
			e.printStackTrace();
		}
	}
}

 

JAVA核心知识点--RMI_第5张图片

客户端如何取得stub对象?

客户端必须取得stub对象,因为客户端必须要调用它的方法,这就得靠RMI registry了。客户端会像查询电话簿一样地搜索,找出上面有相符名称的服务。

RMI会自动将stub解序列化,这就要求客户端在查询服务时一定要有stub类文件,否则将导致stub不能被解序列化。 

package rmi;

import java.rmi.Naming;

public class Client {

	public static void main(String[] args) {
		new Client().go();
	}

	public void go() {
		try {
			//客户端必须使用与服务相同的类型
			//事实上,客户端不需要知道服务实际上的类型
			IRemoteService service = (IRemoteService) Naming.lookup("rmi://127.0.0.1/RemoteHello");
			String s = service.sayHello();
			System.out.println(s);
		} catch (Exception e) {
			e.printStackTrace();
		}
	}
}

 

JAVA核心知识点--RMI_第6张图片

注意事项:

  • 客户端是使用接口来调用stub上的方法,客户端的Java虚拟机必须要有stub类,但客户端不会在程序代码中引用stub类,客户端总是通过接口来操作真正的远程对象。
  • 服务器上必须要有stub和skeleton,以及服务于远程的接口,它会需要stub类是因为stub会被代换成连接在RMI registry上真正的服务。 

你可能感兴趣的:(JAVA核心知识点)