`
gyabooks
  • 浏览: 22987 次
  • 性别: Icon_minigender_1
  • 来自: 北京
社区版块
存档分类
最新评论

Java RMI 实现代码动态下载

阅读更多

博采众生摘要:本译文将向你介绍JavaTMRMI动态类文件下载的应用,学习完本文,你将会对JavaTMRMI有进一步的认识。希望你能参考我的上一篇译文:开始学习Java RMI,远程方法调用-基础篇

你可以点击如下链接访问原文:Dynamic code downloading using JavaTM RMI,codebase tutorial。

声明:未经允许请勿转载,谢谢!

本教程将分如下步骤向你介绍:

1.概要

Java平台一个重要的优点就是可以动态的从一个给定的URL下载Java软件到一个正在运行JVM的独立进程中,该进程通常位于一个不同物理系统中。这样可以让一个远程系统运行一个程序,例如一个Applet,它从来没有被安装到本地的存储介质上。在该文档的前几部分,我们先讨论Applet的codebase,以帮助我们更好的介绍有关Java RMI的codebase。

举例来说,一个运行在浏览器中的虚拟机,可以把java.applet.Applet的子类和其相关类的字节码下载下来(到本地)。运行该浏览器的系统以前从没有运行过该Applet,也没有在本地安装。一旦所有的类从服务端下载完成,浏览器借助本地资源就开始运行这个Applet程序。

Java RMI正是采用了这个优点,下载、运行这些从来没有在本地安装过的类。调用Java RMI的API的虚拟机,不仅仅像那些浏览器中,能够下载任意Java类文件,其中含有那些特定Java RMI存根类,它使借助服务器资源的远程调用的执行成为可能。

Codebase观点源于Java程序语言的ClassLoaders的应用。当一个Java程序使用一个ClassLoader时,那么它需要知道它被允许到那里调用类。通常,一个类调用者和HTTP Server一起使用,Server为Java平台应用提供编译过的类。很可能,你提到第一对有关ClassLoader/codebase就是AppletClassLoader和作为HTML标签<applet>的“codebase”属性。本文档假设你有些Java RMI编程经验,同时写过一些含有applet标签的HTML文件。例如,在HTML源文件中(applet标签)将含有一些类似下面的代码:

<applet height=100 width=100 codebase="myclasses/" code="My.class"> <param name="ticker"> </applet>

2.什么是codebase

类代码址可以为一个源文件,或是一个目录,虚拟机可以由此加载类。举个例子来说,如果你邀请一个朋友到家吃晚饭,你需要告诉你朋友你的居住方向,以便你的朋友能够确定你家的位置。同样,你可以把代码库址(Codebase)看作一个你指给JVM的方向,让JVM能够找到[可能是远程]它需要的类。

你可以把你的classpath看作为是“本地代码库址”,因为它是一系列调用本地代码类目录。当基于本地调用类时,你的classpath环境变量是(JVM的)参照。CLasspath变量可以设定为一个相对,绝对目录或是类文件压缩包。倘若CLASSPATH是一种“本地代码库址”,那么Applets和远程对象使用的codebase也可以认为是一种“远程代码库址”。

3.工作原理

3.1 Applets如何使用代码库址(codebase)

为了能和Applet交互,这个applet和其运行中需要的任何类必须能够被客户端访问。虽然applets也可以通过“ftp://”或是“file:///”地址访问,但是它经常是通过Web服务访问。

  • 1.客户端浏览器请求的一个applet的类在CLASSPATH中无法找到
  • 2.通过HTTP,applet(和它需要其他类)从服务端下载到客户端
  • 3.在客户端执行applet

图一:下载Applets

<applet>标签含有的代码库址(codebase)通常是HTML页面URL的相对地址。

3.2 Java RMI如何使用代码库址(codebase)

使用Java RMI,应用程序能够创建出远程对象,该对象接受从客户端中JVM方法调用。为了能让客户端调用远程对象中的方法,客户端必须采用一种机制来和远程对象交流。Java RMI 使用了一个叫做存根的特殊类,它能够被下载到客户端和远程对象的交流(进行方法的调用),而不是使用(专用)程序使客户端同远程对象的方法进行对话。java.rmi.server.codebase属性代表了一个或是多个URL地址,从该地址那些存根类(和存根需要的其他类)能够被下载。

像applet,那些要进行远程方法调用的类也要从“file:///”地址下载,但是也像applet,一个“file:///”地址通常要求客户端和服务端位于同样的物理主机上,除非URL使用其他的文件系统,像NFS,这样才能变得有效。

通常,那些被用来进行远程方法调用的类,都是通过网络资源访问的,像是HTTP或是FTP服务器。

图二:下载Java RMI 存根类

  • 1. 远程对象代码库址(codebase)是通过在远程对象服务端设定java.rmi.server.codebase属性指定的。在Java RMI 注册表的帮助下,Java RMI 服务端注册了一个远程对象,并绑定了一个名字。服务端JVM中代码库址(codebase)设定给在Java RMI注册表中的远程对象引用提供了注解。

  • 2. Java RMI客户端请求一个(已知)命名的远程对象的引用。客户端使用该引用(远程对象的存根实例)进行对远程对象的方法调用。

  • 3. Java RMI注册表向请求的类返回一个引用(存根实例)。客户端会优先于codebase在本地的classpath中寻找存根类,如果发现了,那么它就会在本地调用该类。然而,如果在本地的classpath找不到该stub的存根类,客户端就会试着从远程对象代码库址(codebase)中检索该类。

  • 4. 客户端从代码库址(codebase)请求类。客户端使用的代码库址(codebase)就是存根实例注解的URL,它是在存根类被注册表加载时注解的。回到第一步1,为导出对象的存根做注解,然后随着绑定的名字被注册到注册表中。

  • 5. 定义的存根类(和其需要的其他类)被下载到客户端。

    注意:第4和5是相同的步骤,当远程对象被一个名字绑定到注册表 中时,注册表就开始调用该远程对象类。当注册表试着调用远程对象的存根类时,从代码库址(codebase)中,它和远程对象一起请求该类的定义。

  • 6. 现在客户端已经具备了调用远程对象方法的所有条件。存根(在这过程中)像一个服务端的远程对象的代理一样;不像applet使用代码库址(codebase)运行代码在本地的虚拟机中,Java RMI 客户端使用远程的代码库址(codebase)运行代码在另一个,可能是远程JVM中。如图三所示:

图三:Java RMI 客户端远程方法调用

4.在Java RMI中利用codebase属性,实现非存根(sub)类的下载

除了下载存根类(stub)和其辅助类到客户端,java.rmi.server.codebase属性还被用来指定其他的,不仅仅是stub类的下载地址。

当客户端调用远程对象的方法时,该方法可能无参或是有许多的参数,根据方法参数类型,这样就可能有三种不同情况发生。

第一种情况,所有的(远程)方法参数(或是返回值)都是原始的数据类型,这样远程对象知道如何的解释他们作为方法的参数,同时也无需检查classpath和codebase属性。

第二种情况,至少有一个参数或是返回值是一个对象,然而远程对象可以在本地的classpath中可以找到该对象类的定义。

第三种情况(如图四,第六步所示),远程方法收到一个对象参数,然而远程对象在本地的classpath中没有找到对象的定义。这种远程方法的调用情况如图四所示。客户端发送的对象类可能是(远程方法)参数类的子类型,它可能是两者其中之一:

  • 一个接口的实现,该接口为方法的参数(或是返回值)类型
  • 一个类的子类,该类为方法的参数(或是返回值)类型

图四:Java RMI客户端远程方法调用,传递一个未知的参数类型的子类型

7. 类似applet的代码库址(codebase),客户端设定的代码库址(codebase),用于其他JVM下载远程类,非远程类和接口地址。如果在客户端的应用中设定了代码库址(codebase)属性,那么客户端在调用子类型时,代码库址(codebase)就被作为参数加到子类型的实例上。如果在客户端没有设定代码库址(codebase),那么远程对象就会错误的使用自己的代码库址(codebase)。

5.命令行例子

在applet情况下,代码库址(codebase)是嵌在网页中的,就如我们在本文的第一部分看到的HTML例子。

在Java RMI应用时,codebase不是依靠一个镶嵌在网页中类的引用实现的,客户端会和Java RMI的注册表沟通获得远程对象的应用。由于远程对象的代码库址(codebase)可以指向任意URL,不能仅是一个相对于已知的URL地址,必须是存根类(stub)和其相关类目录的绝对地址。代码库址(codebase)可以指向:

  • 一个目录地址,该目录中含有类包子目录
  • 一个Jar文件路径,含有类包的目录压缩文件
  • 满足以上条件的多个目录或是多个Jar文件,中间用空格间隔

注意:如果代码库址(codebase)设定为一目录地址,那么结尾一定要是“/”。

例子:

如果你把要下载类在“webvector”HTTP服务器的export目录下(在Web根目录下),那么的你的代码库址(codebase)就该这样设置:

-Djava.rmi.server.codebase=http://webvector/export/

如果你把要下载类放在“webline”HTTP服务器的public目录下(在Web根目录下),一个名字为“mystuff.jar”的Jar文件,你的代码库址(codebase)就该如此设置:

-Djava.rmi.server.codebase=http://webline/public/mystuff.jar

现在我们假设你把要下载的类分为两个文件“myStuff.jar”和“myOtherStuff.jar”,而且这两个文件放在不同的服务器上(名字是:“webfront”和“webwave”),你的代码库址(codebase)属性就该这样设定:

-Djava.rmi.server.codebase="http://webfront/myStuff.jar http://webwave/myOtherStuff.jar"

6.疑难问题解答

如果你的Java RMI 程序配置正确,任何一个可以序列化的类,包含Java RMI 存根类,都是可以被下载下来的。动态的存根(stub)能够正常的下载,需要满足几种状况:

  • A. 通过URL提供的存根类和存根类依赖的任何类能够被客户端可达。
  • B. 在服务程序中通过调用bind或是rebind设定(或是在程序安装的过程中激活)(译注:rebind(String url, Remote obj) 或是bind(String url, Remote obj)),如下情况:
    • 如步骤A中设定的URL同时
    • 如果设定的为一个目录,那么必须是“/”结尾。
  • C. rmiregistry在它相关的classpath中找不到存根类或是其依赖的其他类。这也是为什么我们在注册表调用存根时,给它加上代码库址(codebase)的参数的原因了,在服务端或是安装代码中,作为一个调用的结果。
  • D. 客户端安装的SecurityManager允许存根(stub)下载。在Java 2 SE或是高版本中,这将意味着客户端必须在策略文件中进行合适的配置。

在使用Java RMI的java.rmi.server.codebase系统变量时,有两种经常性的问题,我们将在下边讨论。

6.1 运行Java RMI服务端可能碰到的问题

你碰到的第一个问题可能是收到ClassNotFoundException的异常,当你向注册表绑定(bind或是rebind)一个远程对象和名字时。这种异常通常是由不合法的codebase属性引起的,导致了在注册表中不能定位远程对象的存根(stub)或是存根需要的其他类。

同远程对象本身相比,远程对象的存根(stub)实现了所有同样的接口,这需要特别的注意。因此这些接口,同其他定制的类作为方法参数或是返回值,也必须能够通过指定的代码库址(codebase)下载。

通常,由于忽略了属性设定时URL中末尾“/”,导致这个异常的抛出。其他的一些原因可能是:属性值不是一个URL;URL路径拼写错误或是不正确;设定的URL中存根类(stub)和其相关的类不存在。

这种情况下,你遇到的异常可能是这样:

java.rmi.ServerException: RemoteException occurred in server thread; nested exception is: 
	java.rmi.UnmarshalException: error unmarshalling arguments; nested exception is:
	java.lang.ClassNotFoundException: examples.callback.MessageReceiverImpl_Stub
java.rmi.UnmarshalException: error unmarshalling arguments; nested exception is:
	java.lang.ClassNotFoundException: examples.callback.MessageReceiverImpl_Stub
java.lang.ClassNotFoundException: examples.callback.MessageReceiverImpl_Stub
	at sun.rmi.transport.StreamRemoteCall.exceptionReceivedFromServer(Compiled Code)
	at sun.rmi.transport.StreamRemoteCall.executeCall(Compiled Code)
	at sun.rmi.server.UnicastRef.invoke(Compiled Code)
	at sun.rmi.registry.RegistryImpl_Stub.rebind(Compiled Code)
	at java.rmi.Naming.rebind(Compiled Code)
	at examples.callback.MessageReceiverImpl.main(Compiled Code)
RemoteException occurred in server thread; nested exception is:
	java.rmi.UnmarshalException: error unmarshalling arguments; nested exception is: 
	java.lang.ClassNotFoundException: examples.callback.MessageReceiverImpl_Stub

6.2 运行Java RMI客户端可能碰到的问题

你可能遇到第二个问题,就是在注册表中查找远程对象时,输出ClassNotFoundException的异常。如果你在运行客户端代码时收到这个堆栈异常信息,那么问题可能是你的Java RMI注册表启动时classpath设定的问题。参考 requirement C in section 6.0。这里有一个这样异常例子:

java.rmi.UnmarshalException: Return value class not found; nested exception is:
	java.lang.ClassNotFoundException: MyImpl_Stub
	at sun.rmi.registry.RegistryImpl_Stub.lookup(RegistryImpl_Stub.java:109
	at java.rmi.Naming.lookup(Naming.java:60)
	at RmiClient.main(MyClient.java:28)

其他资源

如果你对代码库址(codebase)还有其他的没有解答的问题,请首先浏览RMI-USER组

你可能也想加入RMI-USER邮件列表中。

alimama_pid="mm_11642003_1480608_3725409"; alimama_titlecolor="0000FF"; alimama_descolor ="000000"; alimama_bgcolor="FFFFFF"; alimama_bordercolor="E6E6E6"; alimama_linkcolor="008000"; alimama_bottomcolor="FFFFFF"; alimama_anglesize="0"; alimama_bgpic="0"; alimama_icon="0"; alimama_sizecode="11"; alimama_width=760; alimama_height=90; alimama_type=2;

分享到:
评论

相关推荐

    java RMI实现代码

    java RMI实现代码。分为客户端和服务器端,有清楚的代码注释。

    RMI实现代码动态下载

    RMI代码动态下载,包含了个简单的http服务,直接就可以运行。

    java RMI技术实现的网络聊天室

    java RMI技术实现的网络聊天室 编译通过,很完整的。代码很有参考价值

    Java RMI实现远程控制程序及源代码

    使用Java的RMI来实现远程控制的小程序,类似qq的远程协助。 本程序是根据网上看到的源代码改写而成,主要在用户界面和服务端与客户端的交互上增加了许多功能,并对代码结构进行了重新组织。里面附有原作者的链接,...

    RMI不依赖其他http服务实现代码动态下载

    通过java6 http轻量级的实现 使RMI不依赖其他http服务实现代码动态下载。

    通过Java RMI实现远程调用的一个简单例子

    源代码 博文链接:https://forchase.iteye.com/blog/1454428

    JAVA RMI 调查报告

    由于Java具有跨平台、代码可移植性、安全高效等广泛而强大的功能,因而在开发网络分布式应用的时候,可以用它自身的机制实现分布式计算,一种基于Java的远程方法调用(RMI)为我们开发企业分布式应用提供了行之有效的...

    Java RMI-IIOP相关源代码

    Java RMI-IIOP相关源代码,附有BAT批处理命令,Java EJB初学者可参考学习,EJB的例子。

    RMI实现大文件传输

    一种解决RMI大文件传输的思路,不知道可行性如何,大家看看,交流交流 两个Eclipse工程,分别作为服务端与客户端,直接可运行,不依赖其他http服务可实现代码动态下载。

    用RMI实现的QQ聊天室(带注册和传文件功能)

    用JavaRMI框架实现,组合了JProgressBar,注意服务器启动用Start.jar不要用Service.jar,客户端是Client.jar可开多个,已经进行过局域网测试(JDK1.5)。注册功能,但要先建个邮件服务器,其中建立一个域,建一个...

    java rmi资源汇总

    rim文本,rmiFile,rmi 聊天室.rar,RMI_callback.rar,rmi_callback.zip,RMI不依赖其他http服务实现代码动态下载.rar,RMI动态下载类分析及代码.rar

    JAVA rmi教学课件

    JAVA RMI很好的课件2 RMI结构 如何使RMI开发者不用考虑调用目的对象是在本地还远程? 通过本地、远程透明性的一种架构来完成,即存根(Stub)和骨架(Skeleton)。 RMI在客户机端使用存根,存根就像服务器端代码的...

    JavaRMI模拟时钟

    这是用Java RMI机制实现的一个模拟时钟,服务器端设置Timer,客户端只是被动接受数据进行显示.RMI的安全策略机制在代码中实现。

    RMI-IIOP Java 源码实例.rar

    RMI-IIOP Java 源码实例,附有BAT批处理命令,Java EJB初学者可参考学习,EJB的例子。

    RMI远程调用视频教材

    RMI是Remote Method Invocation(远程方法调用)的 所写。它允许一个Java程序调用网络中另一台计算机上的Java方法,...实现RMI调用的程序和被调用的方法,都必须是Java代码,即客户端和服务器端都必须通过纯Java实现。

    Java中RMI远程调用

    Java远程方法调用,即Java RMI(Java Remote Method Invocation)是Java编程语言里,一种用于实现远程过程调用的应用程序编程接口。它使客户机上运行的程序可以调用远程服务器上的对象。远程方法调用特性使Java编程...

    BrokerTool_java.rar_brokerto_java源代码 RMI_portfolio_rmi

    名称:RMI BrokerTool ... 完整实现所有功能,包括stock 和 portfolio。 MVC范式,RMI带回调,客户端同步刷新。 内容:src文件夹 -- 所有源代码 server.bat -- 服务端 client.bat -- 客户端

    java-rmi-chat:使用Java RMI创建的简单桌面聊天应用

    使用Java RMI的简单桌面应用程序“ rmi工具测试”提交的源代码来自:

    基于 RMI 的分布式议程服务

    使用 Java RMI 构建一个分布式议程服务(agenda service)。不同的客户应能连接到这一共享的议程服务,并查询、添加和删除议程中的会晤(meeting)安排。服务程序应具备新用户注册、清除某一用户所有会晤安排等管理...

    Isola_Game:使用 Java RMI 实现的 2 人游戏

    目标: 了解 Java RMI 的工作原理理解和实现MVC(模型视图控制器)模式注意:您需要在运行之前编译代码。 运行代码: 如果在同一台机器上运行您将需要 3 个终端(1 个用于服务器,2 个用于玩家#1 和玩家#2) 对于...

Global site tag (gtag.js) - Google Analytics