<!--
google_ad_client = "pub-4615277071069293";
/* 文字连接广告横行A */
google_ad_slot = "7077201342";
google_ad_width = 728;
google_ad_height = 15;
//-->
摘要:本译文翻译Sun的在线文档,为了说明RMI的基础知识,如果你刚开始接触RMI,那么本文对你
很有帮助。本文属于基础教程,学习时请你实际操作该例子。
译注:翻译这篇文件原因,是由于我在学习RMI的过程中疑惑的解决。我不知道为什么要用stub,为什么要把它译成存根
,它到底存在于客户端还是服务端,它由那方(在JVM高于5.0的版本中)产生。在看了这边文档以后,RMI我可以算是有了一定的了解,尤其是codebase tutorial(代码库址教程)学习让我有了更
好的认识。基于此我想把其翻译出来,供大家学习。你可以点击Getting Started Using Java RMI参考原文。这是我得第一篇文章的翻译,希望大家给我意见。如果想对RMI有进一步的讨论,请你在回复
中留下E_Mail。本文用到的源文件可以由CSDN下载频道搜索下载(含使用说明),文件名称为:
Getting Started Using Java RMI 文章使用源代码。
本教程将向你分步展示使用RMI的经典分布式例子“Hello World”。当你学习完这个例子,你可能有许多的疑问。我们
鼓励你到Java RMI FAQ和archives of the RMI-USERS mailing list去寻找答案。如果你乐意加
入RMI-USERS邮件组,请你点击这里。
这个分布式的Hello World例子含有一个可能运行于远程服务的服务器,一个简单的调用远程方法的客户端,客户端调用
远程对象的一个方法,接受到一条“Hello world”消息。
教程按如下部分进行:
教程中将使用的文件为:
- Hello.java -远程接口(方法)定义
- Server.java-实现远程接口的远程对象
- Client.java-调用远程方法的简单客户端
注意:在以下教程中,“远程对象实现”和“实现类”都指向同一个类:example.hello.Server,它
实现了远程接口。
定义远程接口
一个远程对象是指实现了远程接口类的实例。远程接口继承于java.rmi.Remote接口,同时定义了一系列用于远程调用的
方法,每一个方法除了其他应用程序异常以外,还必须显式声明抛出异常java.rmi.RemoteException(或是RemoteException的父类)在throws句子中。
下面是例子远程接口的定义,example.hello.Hello。它定义了一个方法,sayHello,实现向调用者返回一个字符串:
-
packageexample.hello;
-
importjava.rmi.Remote;
-
importjava.rmi.RemoteException;
-
publicinterfaceHelloextendsRemote
- {
-
StringsayHello()throwsRemoteException;
- }
调用远程方法除了和调用本地方法产生一样的问题外,还有其他许多的干扰问题(如网络通信故障和服务器出现问题)
,所以远程方法通过抛出java.rmi.RemoteException异常报告这种失败。想知道关于通信失败和恢复的进一步的内容在分布式系统中,请参考:A Note on Distributed Computing.
远程服务的实现
一个“服务类”,在本文中,是指创建一个实现远程接口对象,导出该对象,并把其用一字符串绑定到RMI注册表中含有
main主方法的类。该含有main方法类实例化了自身,或是实例化其他所有远程对象类。
在本例子中,服务器类中main方法实现远程接口Hello。main方法将完成以下任务:
- 创建和导出远程对象
- 使用Java RMI Registry注册和绑定该远程对象
这是Server类的程序清单,具体的关于源码的描述将在代码后:
-
packageexample.hello;
-
importjava.rmi.registry.Resistry;
-
importjava.rmi.registry.LocateRegistry;
-
importjava.rmi.RemoteException;
-
importjava.rmi.server.UnicastRemoteObject;
-
publicclassServerimplementsHello
- {
-
publicServer(){}
-
publicStringsayHello()
- {
-
return“Hello,World!”;
- }
-
publicstaticvoidmain(Stringargs[])
- {
- Try{
-
Serverobj=newServer
();
-
Hellostub=(Hello)UnicastRemoteObject.explortObject(obj,0);
-
- Registryregistry=LocateRegistry.getRegistry();
- Registry.bind(“Hello”,stub);
- System.err.println(“Serverready”);
-
}catch(Exceptione)
- {
- System.err.println(“Serverexception:”+e.toString());
- e.printStackTrace();
- }
- }
- }
Server类实现了接口Hello,同时也完成了接口中的方法sayHello。方法sayHello不需要再次的声明抛出任何异常,原因
在于其本身就是一个接口方法的实现,既不会抛出RemoteException也不会抛出其他的检查异常。
注意:该类中还可以定义在接口中没有指定的方法,但是这些方法只能够被运行于远程服务的JVM调
用,不能够远程调用。
创建和导出远程对象
在服务器类的main方法中,实现了一个远程的对象以提供服务,除此之外,必须导出远程对象到Java RMI运行中,以便
接受即将到来的远程呼叫,一切完成如下:
Server obj=new Server();
Hello stub=(Hello)UnicastRemoteObject.exportObject(obj,0);
静态方法UnicastRemoteObject.exportObject(obj,0)导出了用于提供给远程的对象,等待着即将到来的在任意端口远程
方法呼叫,同时返回一个为了传给远程客户端的对象桩。导出的结果,就是让运行中的系统可能开始了一个新的服务套接字或是共享一个服务套接字,监控远程方
法调用的呼叫。该返回的桩同样实现了远程接口像远程对象类,它含有主机名称,远程对象用于通信的端口。
注意:从J2SE5.0以后的版本,桩类不再需要rmic桩编译器事先编译产生,除非远程对象要支持JVM低
于5.0的客户端。如果你的应用程序要支持这样的客户端,那么在应用和部署时,就需要为这些远程对象产生桩类提供给远程客户端下载。如何的产生桩类,请查阅
rmic编译器工具文档[ Solaris, Windows]。如何让产生的桩类更好的与你的应用部署结
合起来,请你查阅codebase tutorial(代码库址教程
).
使用Java RMI registry注册远程对象
为了能让调用者(客户端,终端或是Applet)调用远程对象的方法,调用者必须事先获得远程对象的桩。为了自引导,
Java RMI 为应用程序提供了一个注册表API,用于把远程对象的桩绑定到一个名字,这样远程客户端依靠查找该名字就能获得对应的桩。
Java RMI 注册表只是一个允许客户端获得远程对象桩引用的简单名字服务。通常,一个注册表用来(通常也是这样)仅
是定位第一个远程对象,客户端需要用到的。然后,典型的,第一个对象可能反过来为寻找其他的对象提供特殊的应用支持。举例来说,相对另一个远程调用,一
个引用可能用作一个参数或是作为一个返回值。讨论这是如何工作的,请你浏览Applying the Factory Pattern to Java RMI.
一旦远程对象被注册在服务器上,调用者就能就可以查找到该对象通过名字,获得这个对象的引用,然后调用该对象的
方法。
下面Server代码产生了一个本地主机默认端口的注册存根,然后使用其远程对象存根绑定一个名字“Hello”在那个注册
表中:
Registry registry=LocateRegistry.getRegistry();
Registry.bind(“Hello”,stub);
静态无参LocateRegistry.getRegistry返回一个实现远程端口java.rmi.registry.Registry的存根,该存根发送调用到
本地端口为1099的服务器注册表,那时bind()方法就被用来绑定远程对象存根和“Hello”名字在注册表中。
注意:LocateRegistry.getRegistry只是简单的返回一个合适的注册表存根,这个方法不会去检查是
否一个注册表正在运行中。如果在本地1099的端口上没有运行中的注册表,那么bind()方法的调用将会以服务端RemoteException异常而失败。
客户端的实现
客户端产生服务器端的注册表存根,在注册表中通过名字查找远程对象的存根,然后通过远程对象存根调用远程对象方
法sayHello()。
下面是客户端的代码清单:
-
packageexample.hello;
-
importjava.rmi.registry.LocateRegistry;
-
importjava.rmi.registry.Registry;
-
publicclassClient
- {
-
privateClient(){}
-
publicstaticvoidmain(String[]args)
- {
-
Stringhost=(args.length<1)?null:args[0];
-
try{
- Registryregistry=LocateRegistry.getRegistry
(host);
- Hellostub=(Hello)registry.lookup
(“Hello”);
- Stringresponse=stub.sayHello();
- System.out.println(“Response:”+response);
-
}catch(Exceptione)
- {
- System.err.println(“Clientexception:”+e.toString
());
- e.printStackTrace();
- }
- }
- }
通过命令行的指定主机,客户端最先获得静态方法LocateRegistry.getRegistry()返回指定主机注册表存根。如果没有
指定(服务)主机,即主机为null,那么客户端将被暗示使用本地主机。
下一步,从服务端的注册表中,客户端调用注册表存根远程方法lookup()以获得远程对象的存根。
最终,客户端使用远程对象的存根调用远程方法sayHello(),以下的动作当在此时发生:
- 运行中的客户端,依着主机和端口,在远程对象存根中打开了一个到服务端的连接,然后序列化所有调用数据。
- 运行中的服务端,接受呼叫,匹配相应的对象,序列化到客户端的结果(响应“Hello,word”)。
- 运行中的客户端,接受,反序列化,返回结果到调用者。
远程方法调用的返回信息,最终被列印到控制台上。
编译所有源文件
本例中的源文件可以(参考)如下编译:
javac -d destDir Hello.java Server.java Client.java
这里的destDir是指编译class存放地
注意:如果你的服务端需要支持低于5.0的虚拟机版本,那么所有的远程对象类的存根需要使用rmic
编译产生,同时这些存根能够让客户端下载。请参看codebase tutorial(代码库址教程)获得更多信息。
启动registry,server,client
为了完成这个例子,你需要做如下的工作:
- 启动Java RMI registry
- 启动服务端
- 启动客户端
启动注册表服务
要启动注册表服务,只需要在服务端执行rmiregistry命令即可。如果成功,命令没有任何输出,是典型的后台服务。请
你查考工具文档,获得更多的rmiregistry [
Solaris, Windows]的信息。
例子,在Solaris平台:
rmiregistry &
或者在Windows平台:
start rmiregistry
默认的注册服务运行在TCP协议端口1099。如果想改变该端口,需要在命令行中指定端口号。例如,想在Windows平台上
启动注册服务在端口2001上运行,只需:
start rmiregistry 2001
如果注册服务运行在非1099端口,你将需要为LocateRegistry.getRegistry()方法指定设定的端口调用无论是在客户端
或是服务端。例如,注册服务运行在端口是2001的主机上,那么getRegistry()在服务端的调用就该是:
Registry registry=LocateRegistry.getRegistry(2001);
启动服务
启动远程服务,在命令行运行Server类如下:
在Soloaris平台上:
java –classpath classDir –Djava.rmi.server.codebase=file:classDir/
example.hello.Server &
在Windows平台上:
java –classpath classDir –Djava.rmi.server.codebase=file:classDir/
example.hello.Server
这里的classDir是指类文件存放着的根目录(参看destDir在编译源文件
部分)。设定java.rmi.server.codebase属性就是为了让注册表能够调用远程接口(注意”/”结尾非常的重要),关于如何使用这个系统属性,请你参考codebase tutorial(代码库址教程)。
(启动)服务输出应该如下:
Server readey
这个服务继续运行,直到用户(强制)结束(典型的结束该进程)。
运行客户端
一旦服务准备好了,客户端就可以按着如下运行:
java –classpath classDir example.hello.Client
这里的classDir还是类文件存放的根目录(参看destDir在“编译源文件”部分)。
客户端的输出如下:
response: Hello, world!
声明:未经允许,请勿转载本文,谢谢!
<!--
google_ad_client = "pub-4615277071069293";
/* 文字广告-横向A */
google_ad_slot = "2531196800";
google_ad_width = 728;
google_ad_height = 90;
//-->
<!--
google_ad_client = "pub-4615277071069293";
/* 图片广告-横向A */
google_ad_slot = "5730752301";
google_ad_width = 728;
google_ad_height = 90;
//-->
分享到:
相关推荐
Java远程方法调用(Remote Method Invocation,RMI)是Java平台提供的一种机制,它允许一个Java对象调用在不同JVM上的另一个Java对象的方法。RMI是分布式计算的基础,广泛应用于构建分布式应用系统,如服务器端与...
例如,通过RMI-IIOP,开发者可以利用Spring框架来轻松地实现服务的远程调用。Spring提供了一套完整的支持RMI-IIOP的工具和配置,使得集成变得简单而灵活。 在资源包"RMI-IIOP"中,可能包含以下内容: 1. 说明文件:...
Java RMI(Remote Method Invocation,远程方法调用)是Java平台提供的一种用于分布式计算的技术,它允许Java对象在不同的Java虚拟机之间进行交互。RMI是构建分布式应用程序的基础,尤其适用于那些需要跨越网络进行...
远程方法调用(Remote Method Invocation,简称RMI)是Java平台提供的一种用于分布式系统中对象间通信的技术。通过RMI,一个Java对象可以调用在不同JVM(Java虚拟机)上的另一个对象的方法,实现跨网络的透明操作。...
RMI是Java开发分布式应用的重要工具,尤其是在企业级应用中,如服务器端服务的实现、客户端远程调用等场景。 RMI的工作原理基于Java的序列化机制,它可以将对象的状态转换为字节流,通过网络传输到另一台机器上,...
在IT行业中,远程方法调用(Remote Method Invocation, RMI)是Java编程语言中的一个核心特性,它允许Java对象在不同的网络环境中进行交互。RMI是构建分布式应用程序的基础,尤其在企业级应用开发中,如Java ...
在本节"Dubbo视频教程--基础篇--第01节--使用Dubbo对传统工程进行服务化改造的思路介绍"中,我们将深入探讨如何利用Dubbo这一强大的Java框架,将传统的单体应用转变为服务化的架构,以适应现代企业对可扩展性、灵活...
首先,我们要理解Java远程方法调用(Java RMI,Remote Method Invocation)是实现远程协助的基础。RMI允许一个Java对象调用另一个在不同JVM(Java Virtual Machine)上的对象的方法,仿佛它们都在同一个程序中。因此...
10. **现代替代方案**:随着技术的发展,现代的分布式计算框架如Hadoop、Spark和微服务架构等,提供了更高级别的抽象和功能,但RMI仍然是理解分布式系统和远程调用的基础。 学习和理解RMI有助于提升对分布式系统...
在本节"Dubbo视频教程--基础篇--第02节--使用Dubbo对传统工程进行服务化改造"中,我们将深入探讨如何利用Dubbo这一强大的Java开源框架来重构和优化传统的软件工程项目,使其具备微服务架构的优势。Dubbo是阿里巴巴...
1. Java RMI(Remote Method Invocation):Java远程方法调用是实现CS通信的核心技术,它允许对象在不同的JVM之间透明地调用方法,实现了客户端与服务器端的无缝连接。 2. Socket编程:Java的Socket类提供了网络...
解压后,用户可以运行其中的Server和Client程序,亲身体验RMI的远程调用过程。 总的来说,这个主题提供了学习和实践RMI的良好资源,对于理解和掌握Java的分布式计算能力有着重要的价值。通过阅读博客、研究源码和...
`StringBuffer` 可以通过调用 `toString()` 方法转换为 `String` 类型。 - 示例代码展示了如何使用 `StringBuffer` 来构建字符串并将其转换为 `String` 类型。 - **字符串常量与匿名对象** - 字符串常量 `"hello...
分布式程序设计是现代软件开发中的一个重要领域,它允许在多台计算机之间共享资源和执行任务,从而...通过深入学习和实践,你可以更好地掌握RMI在分布式系统中的运用,为构建高效、可扩展的Java应用程序打下坚实基础。
例如,我们可以创建一个名为`MyService`的接口,包含一些远程调用的方法: ```java public interface MyService { String doSomething(String input); } ``` 2. **实现远程接口**:接着,创建该接口的实现类...
这篇博客主要介绍了RMI的基础知识,虽然描述为空,但我们可以推断博主可能详细讲解了如何设置RMI环境,创建远程接口、远程实现类以及客户端和服务端的交互过程。博客可能还涵盖了RMI的基本概念,如注册表、序列化等...
通过这种方式,我们可以在分布式系统中轻松地实现服务的远程调用,同时利用Spring的依赖注入和AOP功能,提高代码的可维护性和可测试性。在实际应用中,还可能需要考虑安全性、性能优化和异常处理等问题,但本文已为...
在Java中,我们可以利用RMI(远程方法调用)、JMS(Java消息服务)和JNDI(Java命名和目录接口)等技术实现分布式通信。 2. 分布式Java应用核心组件 - EJB(Enterprise JavaBeans):提供了一种标准的组件模型,...
RMI提供了透明的远程调用体验,使得分布式系统的开发变得更加简单。 【HESSIAN】 HESSIAN是一个高效的二进制RPC(Remote Procedure Call)协议和库,它支持跨语言通信。Hessian使得Java和非Java应用之间的通信变得...