基于CORBA的分布式对象架构及COM/CORBA集成解析
1. 分布式对象架构的故障转移与负载均衡
在设计分布式对象架构时,故障转移和负载均衡策略的选择很大程度上取决于架构的性质和部署环境。在设计系统时,回顾相关特性并将其与系统需求进行匹配是很有价值的。大多数分布式系统至少能从一个良好的日志系统中获益,并且需要一些基本的激活管理和一致的持久化机制。更复杂的系统则需要更全面的跟踪和负载均衡,以确保系统的健壮性。架构师必须为手头的工作选择最佳的设计元素。
虽然系统管理一直是CORBA产品的薄弱环节,但供应商已经开始提供更复杂的解决方案。随着该技术的成熟和标准化程度的提高,设计用于部署的架构将不再那么依赖于自行开发。在此之前,相关的问题和策略可以作为评估健壮部署需求和设计的指南。
2. COM/CORBA集成概述
1995年,对象管理组织(OMG)发布了COM/CORBA互操作提案请求(RFP),该提案分为两部分。A部分涉及CORBA与商用COM实现之间的互操作,B部分涉及CORBA与当时仍在开发中的DCOM之间的互操作。1996年,OMG批准了COM/CORBA互操作规范的A部分,1998年批准了B部分。目前已有A部分的商业实现。
COM/CORBA集成的目标是利用两种标准的固有优势。从CORBA的角度来看,可以访问基于COM的应用程序(如Excel)和集成开发环境(如Visual Basic)中成熟的图形用户界面(GUI)。从COM的角度来看,可以基于开放架构实现健壮的、平台无关的分布式系统。此外,标准化集成过程还提供了一种高效的、基于组件的方法,以及定义明确的集成接口和可互操作的实现。
3. COM相关概念
- OLE(对象链接与嵌入) :是一种允许文档之间和应用程序之间进行动态交互的基础设施。通过OLE,可以将一个Windows应用程序中创建的文档嵌入到另一个应用程序创建的文档中,本质上实现了应用程序级别的代码重用。
- OLE2 :是OLE的扩展,改进了组件对象模型。它为DCOM和ActiveX奠定了基础,提供了对自动化的支持。
- COM(组件对象模型) :是一个在二进制级别定义组件集成的规范,是OLE、Microsoft事务服务(MTS)和其他Microsoft组件的基础。根据COM规范,接口以C++虚函数表的形式实现,与虚函数表的交互通过IUnknown接口进行,所有COM类都继承自该接口。访问COM接口需要在编译时对接口定义有静态的了解。以下是一个简单的COM接口示例:
//DocManager.idl
[object, uuid(...)]
interface IDocManagenlUnknown {
HRESULT GetDocument([in] long docNum);
}
- DCOM :是COM功能在网络级别的扩展。
- 自动化 :使COM对象能够在运行时进行动态调用,在概念上等同于动态调用接口(DII)。其功能通过IDispatch接口呈现,操作通过接口签名的文本表示进行定位。IDispatch继承自IUnknown,但不允许直接访问IUnknown方法,因此自动化接口不能静态调用。在代码中,自动化接口声明为继承自IDispatch接口的dispinterface类型。例如,Excel的宏语言(Visual BASIC for Applications,VBA)可以调用Microsoft Word的自动化接口。
- 双接口 :是继承自IDispatch接口的COM接口,在功能上既可以静态访问,也可以动态访问。在代码中,双接口声明为继承自IDispatch接口的接口类型。
4. 桥接机制
桥是互操作架构的一种实现,它指定了CORBA和COM如何协同工作。桥接器负责在COM和CORBA对象模型之间进行映射,使用特殊的代理对象(称为视图)使来自外部系统的对象看起来像是本地对象。桥接器可以提供COM对象的CORBA视图,反之亦然。
5. 元模型
为了讨论在CORBA和COM之间指定桥接时涉及的问题,需要考虑它们对象模型的共同点。基于这些共同概念和特性,可以开发一个概念模型,准确表示两个系统的对象模型,即互操作模型。
互操作模型将对象描述为通过发布的接口访问的离散功能单元。对象有一个生命周期,在特定时间点创建和销毁。在对象存在期间,可以通过其引用进行标识。发布的接口根据一组完整描述的接口语义进行定义,并且可以为接口分配一个标识。接口可以根据明确定义的规则由其他接口组成。请求可以使用对象的引用针对特定的对象实例,对象实例通过调用其实现中的所需操作来处理请求。请求的参数可以是对象引用或基本数据类型。
6. 对象生命周期和标识
CORBA和COM对对象生命周期的概念有很大不同。CORBA对象通常是长生命周期的,激活和钝化以透明方式进行。在CORBA对象的整个生命周期中,它可能会多次被激活(加载到服务器内存中)和钝化(以某种持久方式存储)。CORBA世界中的对象概念与其实例化状态是分离的,在其整个生命周期内,包括激活和钝化状态,都可以使用相同的对象引用进行标识。此外,CORBA对象的初始创建和最终销毁是在应用程序设计中明确确定的事件。
相比之下,COM或自动化对象的概念与其实例化状态紧密耦合。COM和自动化对象引用以内存指针的形式实现,对于非活动对象不存在,并且在实例化之间无效。此外,COM和自动化对象由标准工厂和不接受参数的构造函数实例化,通过引用计数来确定其存在与否,因此是隐式销毁的。
如果接口由CORBA对象实现,从COM的角度来看,问题在于保留对象不可变的、终身的CORBA对象引用。可以通过检索并将CORBA对象引用(IOR)字符串化,然后将其存储在文件中来解决。需要注意的是,对象引用存储不被CORBA对象引用封装,如果系统的COM组件中有多个对该对象的引用,只有实现了自己存储功能的引用持有者才能保留CORBA对象引用。
如果接口在COM端实现,问题在于将CORBA对“长生命周期对象”的期望与COM的短暂性相关联。在COM中,对象通过其在内存中的位置进行标识,如果需要保留其状态,则需要以其他方式(如文件)进行标识。由于COM构造函数不接受参数,COM对象在实例化后需要加载其状态。一种解决方案是实现提供工厂功能的COM目标对象,工厂可以在无状态的情况下创建,实例化具有预期状态的实际所需对象,并将其引用返回给CORBA客户端。COM API函数CoGetlnstanceFromFile可以从文件中加载对象。
7. 接口和接口标识
CORBA接口使用OMG IDL进行描述,在运行时通过CORBA接口存储库ID键进行标识,默认情况下,该键是接口的全限定名称。也可以通过在IDL文件中放置
#pragma ID <interface_name> = <GUID>
预处理器指令,使用全局唯一标识符(GUID)作为存储库ID键。
COM和自动化接口使用MIDL进行描述,在运行时通过接口标识符(IIDs,即GUID)进行标识。COM接口是静态类型的,自动化接口存储在类型库中以便动态检索。
需要将OMG IDL映射到MIDL,将CORBA接口存储库ID映射到COM IIDs。OMG IDL到MIDL的映射通过命名约定实现。例如,OMG IDL接口:
module ContentManagement{
module DocumentManagement{
interface Text{
映射到COM接口
IContentManagement_DocumentManagement_Text
、自动化接口
DContentManagement_DocumentManagement_Text
和双接口
DIContentManagement_DocumentManagement_Text
。COM IIDs可以通过一个算法生成,该算法以CORBA接口存储库ID为输入,输出GUID。
8. 接口组合
CORBA接口根据C++风格的继承规则,基于现有接口进行定义,支持单继承和多继承。
COM支持单继承,多继承通过聚合一组接口并使用IUnknown接口上的
Querylnterface(...)
方法进行遍历。
较新的自动化控制器(如Visual Basic)支持聚合,其继承基于COM继承且与之非常相似。对于较旧的版本,继承通过将所有派生方法合并到一个接口中来实现。需要注意的是,自动化和COM接口都用MIDL表示。
CORBA足够灵活,可以以COM和自动化接口在其原生环境中的实现方式进行复制,因此可以实现一组不相交的接口来模拟COM聚合,或者为较旧的自动化控制器实现一个包含所有方法的接口。具体实现由供应商决定。
COM和自动化对CORBA继承的表示较难实现。一个重要的考虑因素是基于COM的接口对其方法的顺序很敏感。在从CORBA到COM的映射中,有以下三条简单规则:
1. 没有父接口的CORBA接口映射到继承自IUnknown的COM接口。
2. 有单个父接口的CORBA接口映射到继承自该父接口的COM接口。
3. 有多个父接口的CORBA接口映射到继承自IUnknown的COM接口。
从CORBA到自动化的映射需要在与所有自动化控制器兼容的同时,保持所有接口的标识,以确保每个接口的功能可用。规则如下:
1. 没有父接口的CORBA接口映射到继承自IDispatch的自动化接口。
2. 有单个父接口的CORBA接口映射到继承自该父接口的自动化接口。
3. 有多个父接口的CORBA接口映射到继承自最左侧父接口(应用排序规则后)的自动化接口,其他父接口的方法按排序顺序包含在接口定义中。为了保留非最左侧父接口的标识,需要再次定义它们的接口。
9. 请求映射
CORBA请求是双向的方法调用交互,实际请求包括目标对象的引用、操作名称和参数。回复包括返回参数,在失败时还包括异常。单向请求没有回复组件。
COM和自动化请求的表达与CORBA请求基本相同,主要区别在于COM请求不返回异常,而是返回一个称为HRESULT的状态参数。
大多数情况下,COM和CORBA之间的请求映射是直接的、一对一的。CORBA单向请求映射到没有返回参数的COM请求。由于COM不支持动态调用,CORBA的DII/DSI相关接口不进行映射。异常需要特殊处理,将在后续章节详细讨论。
10. 参数映射
CORBA接口有三种类型的参数必须显式声明:输入参数传递给目标对象,输出参数从目标对象传递回来,输入输出参数双向传递。类似地,COM和自动化接口支持
[in]
、
[out]
和
[inout]
参数,HRESULT是隐式声明的返回参数。
参数列表在映射过程中基本保持不变,但也有一些例外。为了适应所有COM MIDL方法调用的返回值都是HRESULT这一事实,显式的OMG IDL返回值映射为
[retval,out]
,并放置在所有声明参数之后的参数列表中。如果OMG IDL接口有
raises
子句,则会在COM操作的返回异常列表末尾添加一个映射到用于检索异常信息的机制的参数。异常检索功能将在异常章节中详细解释。
11. 类型映射
-
基本类型映射
:CORBA与COM以及CORBA与自动化之间的基本类型映射几乎是一对一的,但有三个特殊映射需要考虑:
-
当Automation的
long
参数为负数时,将其映射为CORBA的unsigned long
应返回HRESULT DISP_E_OVERFLOW
。 -
当CORBA的
unsigned long
参数大于Automation的long
的最大值时,将其映射为Automation的long
应返回HRESULT DISP_E_OVERFLOW
。 -
当Automation的
long
参数为负数或大于CORBA的unsigned short
的最大值时,将其映射为CORBA的unsigned short
应返回HRESULT DISP_E_OVERFLOW
。
-
当Automation的
CORBA Type | COM Type | Automation Type |
---|---|---|
short | 16-bit signed integer | 16-bit unsigned integer |
long | 32-bit signed integer | 32-bit signed integer |
unsigned short | 16-bit unsigned integer | 16-bit unsigned integer |
unsigned long | 32-bit unsigned integer | 32-bit signed integer |
float | 32-bit IEEE floating point number | 32-bit IEEE floating point number |
double | 64-bit IEEE floating point number | 64-bit IEEE floating point number |
char | 8-bit quantity limited to ISO Latin-1 character set | 8-bit unsigned integer |
char | byte | unsigned char* |
octet | 8-bit opaque data type | 8-bit unsigned integer |
octet | bool | short |
boolean | 8-bit quantity limited to 0 and 1 | VARIANT_BOOL |
string | Null terminated 8-bit character string | BSTR |
bounded string | [string,unique] char* | BSTR |
wstring | Null terminated Unicode string | BSTR |
-
复杂类型映射
:为了在CORBA非对象数据类型(如联合)与其自动化接口对应物之间提供一个知名的接口,互操作规范提供了接口
DICORBAComplexType
。需要注意的是,CORBA非对象数据类型表示为自动化接口,将作为自动化对象实现。自动化对象通过引用传递,而CORBA非对象通过值传递。例如,如果声明一个CORBA结构体myStruct
,在CORBA世界中它总是通过值传递。但如果myStruct
被传递到自动化世界进行进一步分发,所有感兴趣的客户端将引用同一个副本,一个客户端对myStruct
的更改将被所有客户端看到。
CORBA Type | COM Type | Automation Type |
---|---|---|
typedef | typedef | alias |
const | const | alias |
enum | 32-bit signed integer | 16-bit unsigned integer |
struct | struct | DICORBAStruct |
sequence | A struct with a member to declare, a member to declare upward bound, and a pointer to an array | SAFEARRAY |
array | 32-bit IEEE floating point number | SAFEARRAY |
union | 64-bit IEEE floating point number | DICORBAUnion |
any | ICORBAAny | DICORBAAny |
object | lUnknown | IDispatch |
12. 异常映射
异常类型用于错误报告,通常有两种类型:系统异常和用户定义异常。异常的映射并不直接。
-
系统异常
:CORBA系统异常有明确的结构,包含三个数据项:完成状态、主代码和次代码。完成状态是一个枚举,有三个可能的值:YES、NO和MAYBE。主代码是一个32位无符号整数,由CORBA规范指定,用于报告一般错误信息。次代码也是一个32位无符号整数,由供应商定义,用于报告更具体的错误信息。
所有COM操作都返回HRESULT,HRESULT是一个32位值,第一位表示成功或失败,接下来的15位表示错误源,最后16位表示错误本身的信息。所有自动化操作也返回HRESULT。在较新的自动化控制器(如Visual Basic)中,HRESULT的第一位可用于触发内置的错误处理例程。为了改进COM的错误处理能力,自动化在
IDispatch::Invoke()
方法的返回值中提供了一个
EXCEPINFO
结构体,该结构体包含描述错误源的字符串、描述错误本身的字符串、相关帮助文件的ID和帮助文件主题。该结构体供人类使用,不能扩展。可以通过为
IDispatch::Invoke()
参数列表中的可选最后一个参数分配指针来访问
EXCEPINFO
结构体,非空指针表示客户端希望访问
EXCEPINFO
对象。
互操作架构定义了CORBA系统异常主代码到COM HRESULT的映射。标准COM接口
ISupportErrorlnfo
可用于传达CORBA系统异常的次代码和存储库ID,是否使用由供应商决定。自动化系统异常映射到
DICORBASystemException
,为了使用这个接口,需要在操作的参数列表末尾包含一个可选参数。
DICORBASystemException
接口的实现与原生自动化错误处理系统类似,但不会触发内置的自动化错误处理例程,因为HRESULT位不会设置为失败状态。可以简单地使用自动化的原生例程,但原生例程无法访问异常中实际包含的数据。
-
用户定义异常
:CORBA用户定义异常的声明和实现由开发人员负责,用户定义异常必须在OMG IDL操作的
raises
子句中显式声明。
综上所述,COM/CORBA集成涉及多个方面的技术细节,包括对象生命周期管理、接口映射、请求和参数处理以及异常处理等。在实际应用中,需要根据具体需求和场景,合理选择和应用这些技术,以实现高效、健壮的分布式系统。
graph LR
classDef startend fill:#F5EBFF,stroke:#BE8FED,stroke-width:2px
classDef process fill:#E5F6FF,stroke:#73A6FF,stroke-width:2px
classDef decision fill:#FFF6CC,stroke:#FFBC52,stroke-width:2px
A([开始]):::startend --> B{选择集成方向}:::decision
B -->|COM到CORBA| C(处理对象生命周期差异):::process
B -->|CORBA到COM| D(处理接口和标识映射):::process
C --> E(保留CORBA对象引用):::process
D --> F(映射OMG IDL到MIDL):::process
E --> G(处理请求和参数映射):::process
F --> G
G --> H(处理异常映射):::process
H --> I([结束]):::startend
以上流程图展示了COM/CORBA集成的主要步骤,包括选择集成方向、处理对象生命周期差异、接口和标识映射、请求和参数映射以及异常处理等。在具体实现过程中,需要根据实际情况进行详细的配置和调整。
基于CORBA的分布式对象架构及COM/CORBA集成解析
13. 集成优势与价值体现
COM与CORBA的集成带来了多方面的显著优势。首先,从资源利用角度来看,它能够让开发者充分借助现有应用和组件来构建与扩展分布式系统。对于CORBA而言,可接入如Excel、Visual Basic这类基于COM的应用中成熟的GUI,极大提升了用户交互体验;而从COM角度出发,能基于开放架构实现健壮且平台无关的分布式部署,增强了系统的可扩展性和适应性。
其次,标准化的集成过程提供了一种高效的、基于组件的开发途径。这不仅融合了两种模型的优势,还具备定义清晰的集成接口与可互操作的实现,使得不同系统之间的协作更加顺畅,降低了开发和维护的成本。
14. 实际应用场景举例
- 企业级应用开发 :在大型企业的信息系统中,可能存在基于COM的遗留业务系统,同时又有采用CORBA构建的分布式服务。通过COM/CORBA集成,可将两者无缝连接,实现数据共享和业务流程的协同。例如,利用COM组件的成熟功能处理本地业务逻辑,同时借助CORBA的分布式特性实现跨地域、跨部门的服务调用。
- 跨平台应用集成 :对于需要在不同操作系统和平台上运行的应用程序,COM/CORBA集成能够打破平台限制。比如,在Windows平台上使用COM组件开发前端界面,而在Linux或Unix服务器上部署CORBA服务,通过桥接机制实现两者的通信和协作。
15. 集成过程中的挑战与应对策略
- 对象生命周期管理挑战 :如前文所述,CORBA对象和COM对象在生命周期概念上差异较大。为应对这一挑战,在设计系统时,需要仔细规划对象的创建、激活、钝化和销毁过程。对于CORBA对象引用的存储,可通过“stringifying”操作将其转换为字符串并存储在文件中,但要注意多引用情况下的存储管理。对于COM对象,可实现工厂功能的目标对象,确保其能正确加载所需状态。
- 接口映射复杂性 :CORBA和COM在接口定义、继承方式等方面存在诸多不同,导致接口映射较为复杂。在进行映射时,要严格遵循命名约定和映射规则,如将OMG IDL映射到MIDL,将CORBA接口存储库ID映射到COM IIDs。同时,要考虑不同版本自动化控制器的差异,合理实现接口继承和聚合。
- 异常处理难度 :异常映射并不直接,需要开发者深入理解CORBA和COM的异常机制。在处理系统异常时,可利用互操作架构定义的映射关系,结合标准COM接口和自动化接口进行异常信息的传递和处理。对于用户定义异常,要在OMG IDL操作中明确声明,并在代码中进行相应的处理。
16. 未来发展趋势
随着技术的不断发展,COM/CORBA集成可能会朝着更加标准化、自动化和智能化的方向发展。一方面,相关标准会进一步完善,减少开发过程中的自定义配置和手动映射,提高集成的效率和可靠性。另一方面,自动化工具和框架可能会不断涌现,帮助开发者更轻松地完成集成任务。同时,智能化的异常处理和故障恢复机制也将得到加强,提升系统的稳定性和容错能力。
17. 总结
COM/CORBA集成是一项复杂但极具价值的技术,它为分布式系统的开发和集成提供了强大的支持。通过深入理解和掌握对象生命周期管理、接口映射、请求和参数处理以及异常处理等关键技术,开发者能够充分发挥两者的优势,构建出高效、健壮的分布式应用。
在实际操作过程中,要根据具体需求和场景,灵活运用各种技术和策略,同时关注技术的发展趋势,不断优化和改进集成方案。以下是对COM/CORBA集成关键要点的总结表格:
关键方面 | 详细内容 |
---|---|
对象生命周期管理 | CORBA对象长生命周期,与实例化状态解耦;COM对象与实例化状态紧密耦合,需特殊处理引用保留和状态加载 |
接口映射 | 包括OMG IDL到MIDL的映射、接口标识映射、接口继承和聚合方式的处理 |
请求和参数处理 | 请求映射基本一对一,但需考虑单向请求和异常处理;参数列表保持基本不变,但有特殊情况需处理 |
异常处理 | 系统异常和用户定义异常的映射和处理,需借助特定接口和机制 |
graph LR
classDef startend fill:#F5EBFF,stroke:#BE8FED,stroke-width:2px
classDef process fill:#E5F6FF,stroke:#73A6FF,stroke-width:2px
classDef decision fill:#FFF6CC,stroke:#FFBC52,stroke-width:2px
A([应用启动]):::startend --> B{判断是否为COM/CORBA集成环境}:::decision
B -->|是| C(初始化桥接机制):::process
B -->|否| D([使用单一架构]):::startend
C --> E(处理对象生命周期):::process
E --> F(进行接口映射):::process
F --> G(处理请求和参数):::process
G --> H(处理异常情况):::process
H --> I([应用运行结束]):::startend
D --> I
以上流程图展示了应用在不同环境下的处理流程。在COM/CORBA集成环境中,需依次完成桥接机制初始化、对象生命周期处理、接口映射、请求和参数处理以及异常处理等步骤;而在非集成环境下,则使用单一架构运行应用。这有助于开发者清晰把握不同场景下的开发和运行逻辑。
通过对COM/CORBA集成技术的全面剖析,我们可以看到它在分布式系统领域的重要性和潜力。在未来的开发实践中,开发者应持续关注其发展动态,不断探索和创新,以实现更加高效、稳定的系统集成。