由于COM是所有新型Win32应用程序的结构核心,所以通过Java代码使用(或揭示)COM服务的能力就显得尤为重要。Java/COM集成无疑是Microsoft Java编译器以及虚拟机最有趣的特性。Java和COM在它们的模型上是如此相似,所以这个集成在概念上是相当直观的,而且在技术上也能轻松实现无缝结合——为访问COM,几乎不需要编写任何特殊的代码。大多数技术细节都是由编译器和/或虚拟机控制的。最终的结果便是Java程序员可象对待原始Java对象那样对待COM对象。而且COM客户可象使用其他COM服务器那样使用由Java实现的COM服务器。在这里提醒大家,尽管我使用的是通用术语“COM”,但根据扩展,完全可用Java实现一个ActiveX Automation服务器,亦可在Java程序中使用一个ActiveX控件。
Java和COM最引人注目的相似之处就是COM接口与Java的“interface”关键字的关系。这是接近完美的一种相符,因为:
■COM对象揭示出了接口(也只有接口)
■COM接口本身并不具备实施方案;要由揭示出接口的那个COM对象负责它的实施
■COM接口是对语义上相关的一组函数的说明;不会揭示出任何数据
■COM类将COM接口组合到了一起。Java类可实现任意数量的Java接口。
■COM有一个引用对象模型;程序员永远不可能“拥有”一个对象,只能获得对对象一个或多个接口的引用。Java也有一个引用对象模型——对一个对象的引用可“造型”成对它的某个接口的引用。
■COM对象在内存里的“生存时间”取决于使用对象的客户数量;若这个数量变成零,对象就会将自己从内存中删去。在Java中,一个对象的生存时间也由客户的数量决定。若不再有对那个对象的引用,对象就会等候垃圾收集器的处理。
Java与COM之间这种紧密的对应关系不仅使Java程序员可以方便地访问COM特性,也使Java成为编写COM代码的一种有效语言。COM是与语言无关的,但COM开发事实上采用的语言是C++和Visual Basic。同Java相比,C++在进行COM开发时显得更加强大,并可生成更有效的代码,只是它很难使用。Visual Basic比Java简单得多,但它距离基础操作系统太远了,而且它的对象模型并未实现与COM很好的对应(映射)关系。Java是两者之间一种很好的折衷方案。
接下来,让我们对COM开发的一些关键问题进行讨论。编写Java/COM客户和服务器时,这些问题是首先需要弄清楚的。
A.5.1 COM基础
COM是一种二进制规范,致力于实施可相互操作的对象。例如,COM认为一个对象的二进制布局必须能够调用另一个COM对象里的服务。由于是对二进制布局的一种描述,所以只要某种语言能生成这样的一种布局,就可通过它实现COM对象。通常,程序员不必关注象这样的一些低级细节,因为编译器可自动生成正确的布局。例如,假设您的程序是用C++写的,那么大多数编译器都能生成符合COM规范的一张虚拟函数表格。对那些不生成可执行代码的语言,比如VB和Java,在运行期则会自动挂接到COM。
COM库也提供了几个基本的函数,比如用于创建对象或查找系统中一个已注册COM类的函数。
一个组件对象模型的基本目标包括:
■让对象调用其他对象里的服务
■允许新类型对象(或更新对象)无缝插入环境
第一点正是面向对象程序设计要解决的问题:我们有一个客户对象,它能向一个服务器对象发出请求。在这种情况下,“客户”和“服务器”这两个术语是在常规意义上使用的,并非指一些特定的硬件配置。对于任何面向对象的语言,第一个目标都是很容易达到的——只要您的代码是一个完整的代码块,同时实现了服务器对象代码以及客户对象代码。若改变了客户和服务器对象相互间的沟通形式,只需简单地重新编译和链接一遍即可。重新启动应用程序时,它就会自动采用组件的最新版本。
但假若应用程序由一些未在自己控制之下的组件对象构成,情况就会变得迥然有异——我们不能控制它们的源码,而且它们的更新可能完全独立于我们的应用程序进行。例如,当我们在自己的程序里使用由其他厂商开发的ActiveX控件时,就会面临这一情况。控件会安装到我们的系统里,我们的程序能够(在运行期)定位服务器代码,激活对象,同它建立链接,然后使用它。以后,我们可安装控件的新版本,我们的应用程序应该仍然能够运行;即使在最糟的情况下,它也应礼貌地报告一条出错消息,比如“控件未找到”等等;一般不会莫名其妙地挂起或死机。
在这些情况下,我们的组件是在独立的可执行代码文件里实现的:DLL或EXE。若服务器对象在一个独立的可执行代码文件里实现,就需要由操作系统提供的一个标准方法,从而激活这些对象。当然,我们并不想在自己的代码里使用DLL或EXE的物理名称及位置,因为这些参数可能经常发生变化。此时,我们想使用的是由操作系统维护的一些