📄 appa.htm
字号:
com.ms.com包为COM的开发定义了数量众多的类。它支持GUID的使用——Variant(变体)和SafeArray
Automation(安全数组自动)类型——能与ActiveX控件在一个较深的层次打交道,并可控制COM异常。<br>
由于篇幅有限,这里不可能涉及所有这些主题。但我想着重强调一下COM异常的问题。根据规范,几乎所有COM函数都会返回一个HRESULT值,它告诉我们函数调用是否成功,以及失败的原因。但若观察服务器和客户代码中的Java方法签名,就会发现没有HRESULT。相反,我们用函数返回值从一些函数那里取回数据。“虚拟机”(VM)会将Java风格的函数调用转换成COM风格的函数调用,甚至包括返回参数。但假若我们在服务器里调用的一个函数在COM这一级失败,又会在虚拟机里出现什么事情呢?在这种情况下,JVM会认为HRESULT值标志着一次失败,并会产生类com.ms.com.ComFailException的一个固有Java异常。这样一来,我们就可用Java异常控制机制来管理COM错误,而不是检查函数的返回值。<br>
如欲深入了解这个包内包含的类,请参考微软公司的产品文档。<br>
<br>
A.5.5 ActiveX/Beans集成<br>
Java/COM集成一个有趣的结果就是ActiveX/Beans的集成。也就是说,Java Bean可包含到象VB或任何一种Microsoft
Office产品那样的ActiveX容器里。而一个ActiveX控件可包含到象Sun BeanBox这样的Beans容器里。Microsoft
JVM会帮助我们考虑到所有的细节。一个ActiveX控件仅仅是一个COM服务器,它展示了预先定义好的、请求的接口。Bean只是一个特殊的Java类,它遵循特定的编程风格。但在写作本书的时候,这一集成仍然不能算作完美。例如,虚拟机不能将JavaBeans事件映射成为COM事件模型。若希望从ActiveX容器内部的一个Bean里对事件加以控制,Bean必须通过低级技术拦截象鼠标行动这类的系统事件,不能采用标准的JavaBeans委托事件模型。<br>
抛开这个问题不管,ActiveX/Beans集成仍然是非常有趣的。由于牵涉的概念与工具与上面讨论的完全相同,所以请参阅您的Microsoft文档,了解进一步的细节。<br>
<br>
A.5.6 固有方法与程序片的注意事项<br>
固有方法为我们带来了安全问题的一些考虑。若您的Java代码发出对一个固有方法的调用,就相当于将控制权传递到了虚拟机“体系”的外面。固有方法拥有对操作系统的完全访问权限!当然,如果由自己编写固有方法,这正是我们所希望的。但这对程序片来说却是不可接受的——至少不能默许这样做。我们不想看到从因特网远程服务器下载回来的一个程序片自由自在地操作文件系统以及机器的其他敏感区域,除非特别允许它这样做。为了用J/Direct,RNI和COM集成防止此类情况的发生,只有受到信任(委托)的Java代码才有权发出对固有方法的调用。根据程序片的具体使用,必须满足不同的条件才可放行。例如,使用J/Direct的一个程序片必须拥有数字化签名,指出自己受到完全信任。在写作本书的时候,并不是所有这些安全机制都已实现(对于Microsoft
SDK for Java,beta 2版本)。所以当新版本出现以后,请务必留意它的文档说明。<br>
<br>
A.6 CORBA<br>
在大型的分布式应用中,我们的某些要求并非前面讲述的方法能够满足的。举个例子来说,我们可能想同以前遗留下来的数据仓库打交道,或者需要从一个服务器对象里获取服务,无论它的物理位置在哪里。在这些情况下,都要求某种形式的“远程过程调用”(RPC),而且可能要求与语言无关。此时,CORBA可为我们提供很大的帮助。<br>
CORBA并非一种语言特性,而是一种集成技术。它代表着一种具体的规范,各个开发商通过遵守这一规范,可设计出符合CORBA标准的集成产品。CORBA规范是由OMG开发出来的。这家非赢利性的机构致力于定义一个标准框架,从而实现分布式、与语言无关对象的相互操作。<br>
利用CORBA,我们可实现对Java对象以及非Java对象的远程调用,并可与传统的系统进行沟通——采用一种“位置透明”的形式。Java增添了连网支持,是一种优秀的“面向对象”程序设计语言,可构建出图形化和非图形化的应用(程序)。Java和OMG对象模型存在着很好的对应关系;例如,无论Java还是CORBA都实现了“接口”的概念,并且都拥有一个引用(参考)对象模型。<br>
<br>
A.6.1 CORBA基础<br>
由OMG制订的对象相互操作规范通常称为“对象管理体系”(ObjectManagement
Architecture,OMA)。OMA定义了两个组件:“核心对象模型”(Core Object
Model)和“OMA参考体系”(OMA Reference Model)。OMA参考体系定义了一套基层服务结构及机制,实现了对象相互间进行操作的能力。OMA参考体系包括“对象请求代理”(Object
Request Broker,ORB)、“对象服务”(Object Services,也称作CORBAservices)以及一些通用机制。<br>
ORB是对象间相互请求的一条通信总线。进行请求时,毋需关心对方的物理位置在哪里。这意味着在客户代码中看起来象一次方案调用的过程实际是非常复杂的一次操作。首先,必须存在与服务器对象的一条连接途径。而且为了创建一个连接,ORB必须知道具体实现服务器的代码存放在哪里。建好连接后,必须对方法自变量进行“汇集”。例如,将它们转换到一个二进制流里,以便通过网络传送。必须传递的其他信息包括服务器的机器名称、服务器进程以及对那个进程内的服务器对象进行标识的信息等等。最后,这些信息通过一种低级线路协议传递,信息在服务器那一端解码,最后正式执行调用。ORB将所有这些复杂的操作都从程序员眼前隐藏起来了,并使程序员的工作几乎和与调用本地对象的方法一样简单。<br>
并没有硬性规定应如何实现ORB核心,但为了在不同开发商的ORB之间实现一种基本的兼容,OMG定义了一系列服务,它们可通过标准接口访问。<br>
<br>
1. CORBA接口定义语言(IDL)<br>
CORBA是面向语言的透明而设计的:一个客户对象可调用属于不同类的服务器对象方法,无论对方是用何种语言实现的。当然,客户对象事先必须知道由服务器对象揭示的方法名称及签名。这时便要用到IDL。CORBA
IDL是一种与语言无关的设计方法,可用它指定数据类型、属性、操作、接口以及更多的东西。IDL的语法类似于C++或Java语法。下面这张表格为大家总结了三种语言一些通用概念,并展示了它们的对应关系。<br>
<br>
CORBA IDL Java C++<br>
<br>
模块(Module) 包(Package) 命名空间(Namespace)<br>
接口(Interface) 接口(Interface) 纯抽象类(Pure abstract class)<br>
方法(Method) 方法(Method) 成员函数(Member function)<br>
<br>
继承概念也获得了支持——就象C++那样,同样使用冒号运算符。针对需要由服务器和客户实现和使用的属性、方法以及接口,程序员要写出一个IDL描述。随后,IDL会由一个由厂商提供的IDL/Java编译器进行编译,后者会读取IDL源码,并生成相应的Java代码。<br>
IDL编译器是一个相当有用的工具:它不仅生成与IDL等价的Java源码,也会生成用于汇集方法自变量的代码,并可发出远程调用。我们将这种代码称为“根干”(Stub
and Skeleton)代码,它组织成多个Java源文件,而且通常属于同一个Java包的一部分。<br>
<br>
2. 命名服务<br>
命名服务属于CORBA基本服务之一。CORBA对象是通过一个引用访问的。尽管引用信息用我们的眼睛来看没什么意义,但可为引用分配由程序员定义的字串名。这一操作叫作“引用的字串化”。一个叫作“命名服务”(Naming
Service)的OMA组件专门用于执行“字串到对象”以及“对象到字串”转换及映射。由于命名服务扮演了服务器和客户都能查询和操作的一个电话本的角色,所以它作为一个独立的进程运行。创建“对象到字串”映射的过程叫作“绑定一个对象”;删除映射关系的过程叫作“取消绑定”;而让对象引用传递一个字串的过程叫作“解析名称”。<br>
比如在启动的时候,服务器应用可创建一个服务器对象,将对象同命名服务绑定起来,然后等候客户发出请求。客户首先获得一个服务器引用,解析出字串名,然后通过引用发出对服务器的调用。<br>
同样地,“命名服务”规范也属于CORBA的一部分,但实现它的应用程序是由ORB厂商(开发商)提供的。由于厂商不同,我们访问命名服务的方式也可能有所区别。<br>
<br>
A.6.2 一个例子<br>
这儿显示的代码可能并不详尽,因为不同的ORB有不同的方法来访问CORBA服务,所以无论什么例子都要取决于具体的厂商(下例使用了JavaIDL,这是Sun公司的一个免费产品。它配套提供了一个简化版本的ORB、一个命名服务以及一个“IDL→Java”编译器)。除此之外,由于Java仍处在发展初期,所以在不同的Java/CORBA产品里并不是包含了所有CORBA特性。<br>
我们希望实现一个服务器,令其在一些机器上运行,其他机器能向它查询正确的时间。我们也希望实现一个客户,令其请求正确的时间。在这种情况下,我们让两个程序都用Java实现。但在实际应用中,往往分别采用不同的语言。<br>
<br>
1. 编写IDL源码<br>
第一步是为提供的服务编写一个IDL描述。这通常是由服务器程序员完成的。随后,程序员就可用任何语言实现服务器,只需那种语言里存在着一个CORBA
IDL编译器。<br>
IDL文件已分发给客户端的程序员,并成为两种语言间的桥梁。<br>
下面这个例子展示了时间服务器的IDL描述情况:<br>
<br>
1031页上程序<br>
<br>
这是对RemoteTime命名空间内的ExactTime接口的一个声明。该接口由单独一个方法构成,它以字串格式返回当前时间。<br>
<br>
2. 创建根干<br>
第二步是编译IDL,创建Java根干代码。我们将利用这些代码实现客户和服务器。与JavaIDL产品配套提供的工具是idltojava:<br>
idltojava -fserver -fclient RemoteTime.idl<br>
其中两个标记告诉idltojava同时为根和干生成代码。idltojava会生成一个Java包,它在IDL模块、RemoteTime以及生成的Java文件置入RemoteTime子目录后命名。_ExactTimeImplBase.java代表我们用于实现服务器对象的“干”;而_ExactTimeStub.java将用于客户。在ExactTime.java中,用Java方式表示了IDL接口。此外还包含了用到的其他支持文件,例如用于简化访问命名服务的文件。<br>
<br>
3. 实现服务器和客户<br>
大家在下面看到的是服务器端使用的代码。服务器对象是在ExactTimeServer类里实现的。RemoteTimeServer这个应用的作用是:创建一个服务器对象,通过ORB为其注册,指定对象引用时采用的名称,然后“安静”地等候客户发出请求。<br>
<br>
1031-1033页程序<br>
<br>
正如大家看到的那样,服务器对象的实现是非常简单的;它是一个普通的Java类,从IDL编译器生成的“干”代码中继承而来。但在与ORB以及其他CORBA服务进行联系的时候,情况却变得稍微有些复杂。<br>
<br>
4. 一些CORBA服务<br>
这里要简单介绍一下JavaIDL相关代码所做的工作(注意暂时忽略了CORBA代码与不同厂商有关这一事实)。main()的第一行代码用于启动ORB。而且理所当然,这正是服务器对象需要同它进行沟通的原因。就在ORB初始化以后,紧接着就创建了一个服务器对象。实际上,它正式名称应该是“短期服务对象”:从客户那里接收请求,“生存时间”与创建它的进程是相同的。创建好短期服务对象后,就会通过ORB对其进行注册。这意味着ORB已知道它的存在,可将请求转发给它。<br>
到目前为止,我们拥有的全部东西就是一个timeServerObjRef——只有在当前服务器进程里才有效的一个对象引用。下一步是为这个服务对象分配一个字串形式的名字。客户会根据那个名字寻找服务对象。我们通过命名服务(Naming
Service)完成这一操作。首先,我们需要对命名服务的一个对象引用。通过调用resolve_initial_references(),可获得对命名服务的字串式对象引用(在JavaIDL中是“NameService”),并将这个引用返回。这是对采用narrow()方法的一个特定NamingContext引用的模型。我们现在可开始使用命名服务了。<br>
为了将服务对象同一个字串形式的对象引用绑定在一起,我们首先创建一个NameComponent对象,用“ExactTime”进行初始化。“ExactTime”是我们想用于绑定服务对象的名称字串。随后使用rebind()方法,这是受限于对象引用的字串化引用。我们用rebind()分配一个引用——即使它已经存在。而假若引用已经存在,那么bind()会造成一个异常。在CORBA中,名称由一系列NameContext构成——这便是我们为什么要用一个数组将名称与对象引用绑定起来的原因。<br>
服务对象最好准备好由客户使用。此时,服务器进程会进入一种等候状态。同样地,由于它是一种“短期服务”,所以
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -