友情提示:如果本网页打开太慢或显示不完整,请尝试鼠标右键“刷新”本网页!
富士康小说网 返回本书目录 加入书签 我的书架 我的书签 TXT全本下载 『收藏到我的浏览器』

Java编程思想第4版[中文版](PDF格式)-第114部分

快捷操作: 按键盘上方向键 ← 或 → 可快速上下翻页 按键盘上的 Enter 键可回到本书目录页 按键盘上方向键 ↑ 可回到本页顶部! 如果本书没有阅读完,想下次继续接着阅读,可使用上方 "收藏到我的浏览器" 功能 和 "加入书签" 功能!



式,我设置了一个文本框,用它从用户那里接收要相加的值。并用一个标签显示结果,用两个下推按钮分别 

调用 sum()和 clear()方法。最开始,我们声明了一个名为Adder 的对象变量。在Form_Load 子例程中(在窗 

体首次显示时载入),会调用Adder 自动服务器的一个新实例,并对窗体的文本字段进行初始化。一旦用户 

按下“Sum”或者“Clear”按钮,就会调用服务器中对应的方法。  

  

Dim Adder As Object  

  

Private Sub Form_Load()  

    Set Adder = CreateObject(〃JavaAdder。Adder。1〃)  

    Addend。Text = Adder。getAddend  

    Result。Caption = Adder。getResult  

End Sub  

  

Private Sub SumBtn_Click()  

    Adder。setAddend (Addend。Text)  

    Adder。Sum  

    Result。Caption = Adder。getResult  

End Sub  

  

Private Sub ClearBtn_Click()  

    Adder。Clear  

    Addend。Text = Adder。getAddend  

    Result。Caption = Adder。getResult  

End Sub  

  

注意,这段代码根本不知道服务器是用Java 实现的。  



                                                                                             664 


…………………………………………………………Page 666……………………………………………………………

运行这个程序并调用了 CreateObject()函数以后,就会在Windows 注册表里搜索指定的ProgID。在与 

ProgID 有关的信息中,最重要的是Java 类文件的名字。作为一个响应,会启动Java 虚拟机,而且在 JVM 内 

部调用Java 对象的实例。从那个时候开始,JVM 就会自动接管客户和服务器代码之间的交流。  



A。5。4  用 Java 设计  客户  



现在,让我们转到另一侧,并用Java 开发一个 客户。这个程序会调用系统已安装的 服务器内的服 

务。就 目前这个例子来说,我们使用的是在前一个例子里为服务器实现的一个客户。尽管代码在Java 程序员 

的眼中看起来比较熟悉,但在幕后发生的一切却并不寻常。本例使用了用 Java 写成的一个服务器,但它可应 

用于系统内安装的任何 ActiveX 控件、ActiveX Automation 服务器或者 ActiveX 组件——只要我们有一个类 

型库。  

首先,我们将Jactivex 工具应用于服务器的类型库。Jactivex 有一系列选项和开关可供选择。但它最基本 

的形式是读取一个类型库,并生成 Java 源文件。这个源文件保存于我们的windows/java/trustlib 目录中。 

通过下面这行代码,它应用于为外部 Automation 服务器生成的类型库:  

  

jactivex /javatlb JavaAdder。tlb  

  

Jactivex 完成以后,我们再来看看自己的windows/java/trustlib 目录。此时可在其中看到一个新的子目 

录,名为 javaadder。这个目录包含了用于新包的源文件。这是在 Java 里与类型库的功能差不多的一个库。 

这些文件需要使用Microsoft 编译器的专用引导命令:@ 。jactivex 生成多个文件的原因是  使用多个 

实体来描述一个 服务器(另一个原因是我没有对MIDL 文件和 Java/ 工具的使用进行细致的调整)。  

名为Adder。java 的文件等价于MIDL 文件中的一个 coclass 引导命令:它是对一个  类的声明。其他文件 

则是由服务器揭示出来的 接口的 Java 等价物。这些接口(比如Adder_DispatchDefault。java)都属于 

 “遣送”(Dispatch )接口,属于Automation 控制器与Automation 服务器之间的沟通机制的一部分。 

Java/ 集成特性也支持双接口的实现与使用。但是,IDispatch 和双接口的问题已超出了本附录的范围。  

在下面,大家可看到对应的客户代码。第一行只是导入由 jactivex 生成的包。然后创建并使用  

Automation 服务器的一个实例,就象它是一个原始的 Java 类那样。请注意行内的类型模型,其中“例示” 

了 对象(即生成并调用它的一个实例)。这与 对象模型是一致的。在  中,程序员永远不会得到 

对整个对象的一个引用。相反,他们只能拥有对类内实现的一个或多个接口的引用。  

 “例示”Adder 类的一个Java 对象以后,就相当于指示  激活服务器,并创建这个 对象的一个实例。 

但我们随后必须指定自己想使用哪个接口,在由服务器实现的接口中挑选一个。这正是类型模型完成的工 

作。这儿使用的是“默认遣送”接口,它是Automation 控制器用于同一个Automation 服务器通信的标准接 

口。欲了解这方面的细节,请参考由Ibid 编著的《Inside 》。请注意激活服务器并选择一个  接口是 

多么容易!  

  

import javaadder。*;  

  

public class JavaClient {  

  public static void main(String '' args) {  

    Adder_DispatchDefault iAdder =  

         (Adder_DispatchDefault) new Adder();  

    iAdder。setAddend(3);  

    iAdder。sum();  

    iAdder。sum();  

    iAdder。sum();  

    System。out。println(iAdder。getResult());  

  }  

}  

  

现在,我们可以编译它,并开始运行程序。  

  

1。 。ms。 包  

。ms。包为  的开发定义了数量众多的类。它支持GUID 的使用——Variant (变体)和SafeArray  



                                                                                   665 


…………………………………………………………Page 667……………………………………………………………

Automation (安全数组自动)类型——能与ActiveX 控件在一个较深的层次打交道,并可控制  异常。  

由于篇幅有限,这里不可能涉及所有这些主题。但我想着重强调一下 异常的问题。根据规范,几乎所有 

 函数都会返回一个 HRESULT 值,它告诉我们函数调用是否成功,以及失败的原因。但若观察服务器和客 

户代码中的 Java 方法签名,就会发现没有HRESULT 。相反,我们用函数返回值从一些函数那里取回数据。 

 “虚拟机”(VM )会将Java 风格的函数调用转换成  风格的函数调用,甚至包括返回参数。但假若我们在 

服务器里调用的一个函数在 这一级失败,又会在虚拟机里出现什么事情呢?在这种情况下,JVM 会认为 

HRESULT 值标志着一次失败,并会产生类。ms。。FailException 的一个固有 Java 异常。这样一来, 

我们就可用 Java 异常控制机制来管理 错误,而不是检查函数的返回值。  

如欲深入了解这个包内包含的类,请参考微软公司的产品文档。  



A。5。5 ActiveX/Beans 集成  



Java/ 集成一个有趣的结果就是ActiveX/Beans 的集成。也就是说,Java Bean 可包含到象 VB或任何一种 

Microsoft Office 产品那样的 ActiveX 容器里。而一个ActiveX 控件可包含到象Sun BeanBox 这样的Beans 

容器里。Microsoft JVM 会帮助我们考虑到所有的细节。一个 ActiveX 控件仅仅是一个 服务器,它展示 

了预先定义好的、请求的接口。Bean 只是一个特殊的Java 类,它遵循特定的编程风格。但在写作本书的时 

候,这一集成仍然不能算作完美。例如,虚拟机不能将JavaBeans 事件映射成为 事件模型。若希望从 

ActiveX 容器内部的一个Bean 里对事件加以控制,Bean 必须通过低级技术拦截象鼠标行动这类的系统事件, 

不能采用标准的JavaBeans 委托事件模型。  

抛开这个问题不管,ActiveX/Beans 集成仍然是非常有趣的。由于牵涉的概念与工具与上面讨论的完全相 

同,所以请参阅您的Microsoft 文档,了解进一步的细节。  



A。5。6  固有方法与程序片的注意事项  



固有方法为我们带来了安全问题的一些考虑。若您的 Java 代码发出对一个固有方法的调用,就相当于将控制 

权传递到了虚拟机“体系”的外面。固有方法拥有对操作系统的完全访问权限!当然,如果由自己编写固有 

方法,这正是我们所希望的。但这对程序片来说却是不可接受的——至少不能默许这样做。我们不想看到从 

因特网远程服务器下载回来的一个程序片自由自在地操作文件系统以及机器的其他敏感区域,除非特别允许 

它这样做。为了用 J/Direct ,RNI 和 集成防止此类情况的发生,只有受到信任(委托)的 Java 代码才有 

权发出对固有方法的调用。根据程序片的具体使用,必须满足不同的条件才可放行。例如,使用 J/Direct 的 

一个程序片必须拥有数字化签名,指出自己受到完全信任。在写作本书的时候,并不是所有这些安全机制都 

已实现(对于Microsoft SDK for Java ,beta 2 版本)。所以当新版本出现以后,请务必留意它的文档说 

明。  



A。6 CORBA   



在大型的分布式应用中,我们的某些要求并非前面讲述的方法能够满足的。举个例子来说,我们可能想同以 

前遗留下来的数据仓库打交道,或者需要从一个服务器对象里获取服务,无论它的物理位置在哪里。在这些 

情况下,都要求某种形式的“远程过程调用” (RPC),而且可能要求与语言无关。此时,CORBA 可为我们提 

供很大的帮助。  

CORBA 并非一种语言特性,而是一种集成技术。它代表着一种具体的规范,各个开发商通过遵守这一规范, 

可设计出符合CORBA 标准的集成产品。CORBA 规范是由OMG 开发出来的。这家非赢利性的机构致力于定义一 

个标准框架,从而实现分布式、与语言无关对象的相互操作。  

利用CORBA,我们可实现对Java 对象以及非 Java 对象的远程调用,并可与传统的系统进行沟通——采用一 

种“位置透明”的形式。Java 增添了连网支持,是一种优秀的“面向对象”程序设计语言,可构建出图形化 

和非图形化的应用(程序)。Java 和OMG 对象模型存在着很好的对应关系;例如,无论 Java 还是CORBA 都 

实现了“接口”的概念,并且都拥有一个引用(参考)对象模型。  



A。6。1 CORBA 基础  



由OMG 制订的对象相互操作规范通常称为“对象管理体系”(ObjectManagement Architecture,OMA)。OMA 

定义了两个组件:“核心对象模型”(Core Object Model)和“OMA 参考体系”(OMA Reference  

Model)。OMA 参考体系定义了一套基层服务结构及机制,实现了对象相互间进行操作的能力。OMA 参考体系 

包括“对象请求代理”(Object Request Broker,ORB)、“对象服务”(Object Services,也称作 



                                                                  666 


…………………………………………………………Page 668……………………………………………………………

CORBAservices )以及一些通用机制。  

ORB 是对象间相互请求的一条通信总线。进行请求时,毋需关心对方的物理位置在哪里。这意味着在客户代 

码中看起来象一次方案调用的过程实际是非常复杂的一次操作。首先,必须存在与服务器对象的一条连接途 

径。而且为了创建一个连接,ORB 必须知道具体实现服务器的代码存放在哪里。建好连接后,必须对方法自 

变量进行“汇集”。例如,将它们转换到一个二进制流里,以便通过网络传送。必须传递的其他信息包括服 

务器的机器名称、服务器进程以及对那个进程内的服务器对象进行标识的信息等等。最后,这些信息通过一 

种低级线路协议传递,信息在服务器那一端解码,最后正式执行调用。ORB 将所有这些复杂的操作都从程序 

员眼前隐藏起来了,并使程序员的工作几乎和与调用本地对象的方法一样简单。  

并没有硬性规定应如何实现ORB 核心,但为了在不同开发商的 ORB 之间实现一种基本的兼容,OMG 定义了一 

系列服务,它们可通过标准接口访问。  

  

1。 CORBA 接口定义语言(IDL)  

CORBA 是面向语言的透明而设计的:一个客户对象可调用属于不同类的服务器对象方法,无论对方是用何种 

语言实现的。当然,客户对象事先必须知道由服务器对象揭示的方法名称及签名。这时便要用到 IDL。CORBA  

IDL是一种与语言无关的设计方法,可用它指定数据类型、属性、操作、接口以及更多的东西。IDL 的语法类 

似于C++或 Java 语法。下面这张表格为大家总结了三种语言一些通用概念,并展示了它们的对应关系。  

  

CORBA IDL Java C++  

  

模块(Module) 包(Package) 命名空间(Namespace)  

接口(Interface) 接口(Interface) 纯抽象类(Pure abstract class)  

方法(Method) 方法(Method) 成员函数(Member function)  

  

继承概念也获得了支持——就象C++那样,同样使用冒号运算符。针对需要由服务器和客户实现和使用的属 

性、方法以及接口,程序员要写出一个 IDL描述。随后,IDL会由一个由厂商提供的 IDL/Java 编译器进行编 

译,后者会读取 IDL源码,并生成相应的Java 代码。  

IDL编译器是一个相当有用的工具:它不仅生成与 IDL等价的 Java 源码,也会生成用于汇集方法自变量的代 

码,并可发出远程调用。我们将这种代码称为“根干”(Stub and Skeleton)代码,它组织成多个Java 源 

文件,而且通常属于同一个Java 包的一部分。  

  

2。 命名服务  

命名服务属于CORBA 基本服务之一。CORBA 对象是通过一个引用访问的。尽管引用信息用我们的眼睛来看没 

什么意义,但可为引用分配由程序员定义的字串名。这一操作叫作“引用的字串化”。一个叫作“命名服 

务”(Naming Service)的OMA 组件专门用于执行“字串到对象”以及“对象到字串”转换及映射。由于命 

名服务扮演了服务器和客户都能查询和操作的一个电话本的角色,所以它作为一个独立的进程运行。创建 

 “对象到字串”映射的过程叫作“绑定一个对象”;删除映射关系的过程叫作“取消绑定”;而让对象引用 

传递一个字串的过程叫作“解析名称”。  

比如在启动的时候,服务器应用可创建一个服务器对象,将对象同命名服务绑定起来,然后等候客户发出请 

求。客户首先获得一个服务器引用,解析出字串名,然后通过引用发出对服务器的调用。  

同样地,“命名服务”规范也属于CORBA 的一部分,但实现它的应用程序是由ORB 厂商(开发商)提供的。 

由于厂商不同,我们访问命名服务的方式也可能有所区别。  



A。6。2  一个例子  



这儿显示的代码可能并不详尽,因为不同的ORB 有不同的方法来访问CORBA 服务,所以无论什么例子都要取 

决于具体的厂商(下例使用了JavaIDL,这是 Sun 公司的一个免费产品。它配套提供了一个简化版本的ORB、 

一个命名服务以及一个“IDL→Java ”编译器)。除此之外,由于 Java 仍处在发展初期,所以在不同的 

Java/CORBA 产品里并不是包含了所有 CORBA 特性。  

我们希望实现一个服务器,令其在一些机器上运行,其他机器能向它查询正确的时间。我们也希望实现一个 

客户,令其请求正确的时间。在这种情况下,我们让两个程序都用Java 实现。但在实际应用中,往往分别采 

用不同的语言。  

  

1。 编写 IDL源码  



                                                                       667 


…………………………………………………………Page 669……………………………………………………………

第一步是为提供的服务编写一个 IDL描述。这通常是由服务器程序员完成的。随后,程序员就可用任何语言 

实现服务器,只需那种语言里存在着一个CORBA IDL 编译器。  

IDL文件已分发给客户端的程序员,并成为两种语言间的桥梁。  

下面这个例子展示了时间服务器的 IDL描述情况:  

  

module RemoteTime {  

   interface ExactTime {  

      string getTime();  

   };  

};  

  

这是对 RemoteTime 命名空间内的 ExactTime 接口的一个声明。该接口由单独一个方法构成,它以字串格式返 

回当前时间。  

  

2。 创建根干  

第二步是编译 IDL,创建Java 根干代码。我们将利用这些代码实现客户和服务器。与JavaIDL 产品配套提供 

的工具是idltojava:  

idltojava …fserver …fclient RemoteTime。idl  

其中两个标记告诉 idltojava 同时为根和干生成代码。idltojava 会生成一个 Java 包,它在 IDL模块、 

RemoteTime 以及生成的Java 文件置入 RemoteTime 子目录后命名。_ExactTimeImplBase。java 代表我们用于 

实现服务器对象的“干”;而_ExactTimeStub。java 将用于客户。在ExactTime。java 中,用Java 方式表示 

了IDL 接口。此外还包含了用到的其他支持文件,例如用于简化访问命名服务的文件。  

  

3。 实现服务器和客户  

大家在下面看到的是服务器端使用的代码。服务器对象是在ExactTimeServer 类里实现的。 

RemoteTimeServer 这个应用的作用是:创建一个服务器对象,通过 ORB 为其注册,指定对象引用时采用的名 

称,然后“安静”地等候客户发出请求。  

  

import RemoteTime。*;  

  

import org。omg。CosNaming。*;  

import org。omg。CosNaming。NamingContextPackage。*;  

import org。omg。CORBA。*;  

  

import java。util。*;  

import java。text。*;  

  

// Server object implementation  

class ExactTimeServer extends _ExactTimeImplBase{  

  public String getTime(){  

    return DateFormat。  

        getTimeInstance(DateFormat。FULL)。  

          format(new Date(  

              System。currentTimeMillis()));  

  }  

}  

  

// Remote application implementation  

public class RemoteTimeServer {  

  public static void main(String args'')  {  

    try {  

      // ORB creation and initialization:  



                                                                                             668 


…………………………………………………………Page 670……………………………………………………………

      ORB orb = ORB。init(args; null);  

      // Create the server object and register it:  

      ExactTimeServer timeServerObjRef =   

        new ExactTimeServer();  

      orb。connect(timeServerObjRef);  

      // Get the root naming context:  

      org。omg。CORBA。Object objRef =   

        orb。resolve_initial_references(  

          〃NameService〃);  

      NamingContext ncRef =   

        NamingContextHelper。narrow(objRef);  

      // Assign a string name to the   

      // object reference (binding):  

      Nameponent nc =   

        new Nameponent(〃ExactTime〃; 〃〃);  

      Nameponent path'' = {nc};  

      ncRef。rebind(path; timeServerObjRef);  

      // Wait for client requests:  

      java。lang。Object sync =  

        new java。lang。Object();  

      synchronized(sync){  

        sync。wait();  

      }  

    }  

    catch (Exception e)  {  

      System。out。println(  

         〃Remote Time server error: 〃 + e);  

      e。printStackTrace(System。out);  

    }  

  }  

}  

  

正如大家看到的那样,服务器对象的实现是非常简单的;它是一个普通的 Java 类,从 I
返回目录 上一页 下一页 回到顶部 10 9
快捷操作: 按键盘上方向键 ← 或 → 可快速上下翻页 按键盘上的 Enter 键可回到本书目录页 按键盘上方向键 ↑ 可回到本页顶部!
温馨提示: 温看小说的同时发表评论,说出自己的看法和其它小伙伴们分享也不错哦!发表书评还可以获得积分和经验奖励,认真写原创书评 被采纳为精评可以获得大量金币、积分和经验奖励哦!