失眠网,内容丰富有趣,生活中的好帮手!
失眠网 > Java RMI 入门指南

Java RMI 入门指南

时间:2020-08-10 05:16:40

相关推荐

Java RMI 入门指南

RMI全称是RemoteMethodInvocation-远程方法调用,JavaRMI在JDK1.1中实现的,其威力就体现在它强大的开发分布式网络应用的能力上,是纯Java的网络分布式应用系统的核心解决方案之一。其实它可以被看作是RPC的Java版本。但是传统RPC并不能很好地应用于分布式对象系统。而JavaRMI则支持存储于不同地址空间的程序级对象之间彼此进行通信,实现远程对象之间的无缝远程调用。

RMI目前使用Java远程消息交换协议JRMP(JavaRemoteMessagingProtocol)进行通信。由于JRMP是专为Java对象制定的,JavaRMI具有Java的"WriteOnce,RunAnywhere"的优点,是分布式应用系统的百分之百纯Java解决方案。用JavaRMI开发的应用系统可以部署在任何支持JRE(JavaRunEnvironmentJava,运行环境)的平台上。但由于JRMP是专为Java对象制定的,因此,RMI对于用非Java语言开发的应用系统的支持不足。不能与用非Java语言书写的对象进行通信。

RMI可利用标准Java本机方法接口JNI与现有的和原有的系统相连接。RMI还可利用标准JDBC包与现有的关系数据库连接。RMI/JNI和RMI/JDBC相结合,可帮助您利用RMI与目前使用非Java语言的现有服务器进行通信,而且在您需要时可扩展Java在这些服务器上的使用。RMI可帮助您在扩展使用时充分利用Java的强大功能。

一、RMI(远程方法调用)的组成

一个正常工作的RMI系统由下面几个部分组成:

·远程服务的接口定义

·远程服务接口的具体实现

·桩(Stub)和框架(Skeleton)文件

·一个运行远程服务的服务器

·一个RMI命名服务,它允许客户端去发现这个远程服务

·类文件的提供者(一个HTTP或者FTP服务器)

·一个需要这个远程服务的客户端程序

二、RMI(远程方法调用)原理示意图

方法调用从客户对象经占位程序(Stub)、远程引用层(RemoteReferenceLayer)和传输层(TransportLayer)向下,传递给主机,然后再次经传输层,向上穿过远程调用层和骨干网(Skeleton),到达服务器对象。占位程序扮演着远程服务器对象的代理的角色,使该对象可被客户激活。远程引用层处理语义、管理单一或多重对象的通信,决定调用是应发往一个服务器还是多个。传输层管理实际的连接,并且追踪可以接受方法调用的远程对象。服务器端的骨干网完成对服务器对象实际的方法调用,并获取返回值。返回值向下经远程引用层、服务器端的传输层传递回客户端,再向上经传输层和远程调用层返回。最后,占位程序获得返回值。

要完成以上步骤需要有以下几个步骤:

1、生成一个远程接口

2、实现远程对象(服务器端程序)

3、生成占位程序和骨干网(服务器端程序)

4、编写服务器程序

5、编写客户程序

6、注册远程对象

7、启动远程对象

以下用一个最简单的Hello的示例来介绍RMI的应用。

1:定义一个远程接口

IHello.java代码如下:

import java.rmi.Remote;

public interface IHello extends Remote{

public StringsayHello(Stringname) throws java.rmi.RemoteException;

}

2:实现远程的接口(服务端就在此远程接口的实现类中)

HelloImpl.java代码如下:

import java.rmi.RemoteException;

import java.rmi.server.UnicastRemoteObject;

public class HelloImpl extends UnicastRemoteObject implements IHello{

// 这个实现必须有一个显式的构造函数,并且要抛出一个RemoteException异常

protected HelloImpl() throws RemoteException{

super ();

}

/**

*说明清楚此属性的业务含义

*/

private static final long serialVersionUID = 4077329331699640331L ;

public StringsayHello(Stringname) throws RemoteException{

return " Hello " + name + " ^_^ " ;

}

public static void main(String[]args){

try {

IHellohello = new HelloImpl();

java.rmi.Naming.rebind( " rmi://localhost:1099/hello " ,hello);

System.out.print( " Ready " );

} catch (Exceptione){

e.printStackTrace();

}

}

}

3:新建RMI客户端调用程序

Hello_RMI_Client.java代码如下:

import java.rmi.Naming;

public class Hello_RMI_Client{

public static void main(String[]args){

try {

IHellohello = (IHello)Naming.lookup( " rmi://localhost:1099/hello " );

System.out.println(hello.sayHello( " zhangxianxin " ));

} catch (Exceptione){

e.printStackTrace();

}

}

}

4:编译并运行

4.1用javac命令编译IHello.java、HelloImpl.java、Hello_RMI_Client.java

>javac*.java

4.2用rmic命令生成桩和框架文件

>rmicHelloImpl

成功执行完上面的命令可以发现生成一个HelloImpl_stub.class文件,如果JDK是使用Java2SDK,那么还可以发现多出一个HelloImpl_Skel.class文件。如果服务端程序与客户端程序在同一台机器上并在同一目录中,则可以省略掉接口实现类生成的桩和框架文件,但这就失去了使用RMI的意义,而如果要在不同的JVM上运行时,客户端程序就必须得依靠服务端运程方法实现的桩和框架文件以及接口类。

4.3运行注册程序RMIRegistry,必须在包含刚写的类的目录下运行这个注册程序。

>rmiregistry

注册程序开始运行了,不要管他,现在切换到另外一个控制台运行服务器

4.4运行服务器HelloImpl

>javaHelloImpl

当启动成功出现Ready......这个服务器就开始工作了,把接口的实现加载到内存等待客户端的联接。现在切换到第三个控制台,启动我们的客户端。

4.5启动客户端:为了在其他的机器运行客户端程序你需要一个远程接口(IHello.class)和一个stub(HelloImpl_Stub.class)。使用如下命令运行客户端

>javaHello_RMI_Client

当运行成功会在控制台打印:Hellozhangxianxin^_^

备注:如果不想在控制台上开启RMI注册程序RMIRegistry的话,可在RMI服务类程序中添加LocateRegistry.createRegistry(1099);如下所示:

修改后的HelloImpl.java代码如下:

import java.rmi.RemoteException;

import java.rmi.registry.LocateRegistry;

import java.rmi.server.UnicastRemoteObject;

public class HelloImpl extends UnicastRemoteObject implements IHello{

// 这个实现必须有一个显式的构造函数,并且要抛出一个RemoteException异常

protected HelloImpl() throws RemoteException{

super ();

}

private static final long serialVersionUID = 4077329331699640331L ;

public StringsayHello(Stringname) throws RemoteException{

return " Hello " + name + " ^_^ " ;

}

public static void main(String[]args){

try {

IHellohello = new HelloImpl();

LocateRegistry.createRegistry( 1099 ); // 加上此程序,就可以不要在控制台上开启RMI的注册程序,1099是RMI服务监视的默认端口

java.rmi.Naming.rebind( " rmi://localhost:1099/hello " ,hello);

System.out.print( " Ready " );

} catch (Exceptione){

e.printStackTrace();

}

}

}

实例

实现简单的查单词功能,一台应用服务器以RMI的方式向客户端提供英译汉词典的服务。

创建一个简单的Java分布式远程方法调用程序可以按以下几个步骤操作:

1)定义远程接口

[java]view plain copy/** *功能说明:定义一个远程接口,必须继承Remote接口,其中需要远程调用的方法必须抛出RemoteException异常 *作者:gangwazi *创建时间:-6-27 */ publicinterfaceWordTranslateextendsRemote{ /** *@paramstr需要被翻译的单词 *@return英汉互译后的内容,如果词典中不包含此单词返回null */ publicStringtranslate(Stringstr)throwsRemoteException; }

2)实现远程接口

[java]view plain copy/** *功能说明:远程接口的实现 *作者:gangwazi *创建时间:-6-27 */ publicclassWordTranslateImplextendsUnicastRemoteObjectimplementsWordTranslate{ privatestaticfinallongserialVersionUID=1L; publicMap<String,String>wordMap=newHashMap<String,String>(); //因为UnicastRemoteObject的构造方法抛出了RemoteException异常,因此这里默认的构造方法必须写,必须声明抛出RemoteException异常 publicWordTranslateImpl()throwsRemoteException{ super(); wordMap.put("China","n.中国"); wordMap.put("Japan","n.日本"); wordMap.put("German","德国"); wordMap.put("list","n.列表;v.列出"); wordMap.put("egg","n.鸡蛋"); wordMap.put("map","n.地图"); wordMap.put("translate","v.翻译"); wordMap.put("banana","n.香蕉"); wordMap.put("apple","n.苹果"); wordMap.put("orange","n.橘子"); wordMap.put("milk","n.牛奶"); wordMap.put("water","n.水"); wordMap.put("drink","v.喝,饮"); } @Override publicStringtranslate(Stringstr)throwsRemoteException{ if(wordMap.containsKey(str)){ returnwordMap.get(str); }else{ returnnull; } } } 由于只是简单的示例,故词典使用map来存储,当然也可以构造专门的词典文件或者从数据库中查询。

3)编写服务器类

[java]view plain copy/** *功能说明:创建RMI注册表,启动RMI服务,并将远程对象注册到RMI注册表中。 *作者:gangwazi *创建时间:-6-27 */ publicclassWordTranslateServer{ publicstaticvoidmain(String[]args){ try{ //创建一个远程对象 WordTranslaterTranslate=newWordTranslateImpl(); //本地主机上的远程对象注册表Registry的实例,并指定端口为5555,这一步必不可少(Java默认端口是1099), //必不可缺的一步,缺少注册表创建,则无法绑定对象到远程注册表上 LocateRegistry.createRegistry(5555); //把远程对象注册到RMI注册服务器上,并命名为RTranslate //绑定的URL标准格式为:rmi://host:port/name(其中协议名可以省略) Naming.bind("rmi://localhost:5555/RTranslate",rTranslate); System.out.println(">>>>>INFO:远程WorldTranslate对象绑定成功!"); }catch(RemoteExceptione){ System.out.println("创建远程对象发生异常!"); e.printStackTrace(); }catch(MalformedURLExceptione){ System.out.println("发生URL畸形异常!"); e.printStackTrace(); }catch(AlreadyBoundExceptione){ System.out.println("发生重复绑定对象异常!"); e.printStackTrace(); } } }

4)编写客户端类

[java]view plain copy/** *功能说明:客户端测试,在客户端调用远程对象上的远程方法,并返回结果。 *作者:gangwazi *创建时间:-6-27 */ publicclassWorldTranslateClient{ publicstaticvoidmain(String[]args){ try{ //在RMI服务注册表中查找名称为RTranslate的对象,并调用其上的方法 WordTranslaterTranslate=(WordTranslate)Naming.lookup("rmi://202.117.10.64:5555/RTranslate"); System.out.print("查询单词China----------->"); System.out.println(rTranslate.translate("China")); System.out.print("查询单词list----------->"); System.out.println(rTranslate.translate("list")); System.out.print("查询单词present----------->"); System.out.println(rTranslate.translate("present")); System.out.print("查询单词banana----------->"); System.out.println(rTranslate.translate("banana")); System.out.print("查询单词util----------->"); System.out.println(rTranslate.translate("util")); System.out.print("查询单词drink----------->"); System.out.println(rTranslate.translate("drink")); }catch(MalformedURLExceptione){ //TODOAuto-generatedcatchblock e.printStackTrace(); }catch(RemoteExceptione){ //TODOAuto-generatedcatchblock e.printStackTrace(); }catch(NotBoundExceptione){ //TODOAuto-generatedcatchblock e.printStackTrace(); } } }

4. 运行结果

服务器端和客户端分别运行在两台机子上

服务器端运行结果

客户端运行结果

如果觉得《Java RMI 入门指南》对你有帮助,请点赞、收藏,并留下你的观点哦!

本内容不代表本网观点和政治立场,如有侵犯你的权益请联系我们处理。
网友评论
网友评论仅供其表达个人看法,并不表明网站立场。