级别: 初级 菅 骁翔 (jianxx@cn.ibm.com), 软件工程师, IBM
2009 年 5 月 25 日 服务组件体系结构(Service Component Architecture,SCA)是下一代编程模型,此编程模型提供了动态调用模式。用户可以在运行时指定 SCA 绑定地址以调用不同的服务,从而达到动态调用的效果。本文深入阐述了如何在 SCA 编程模型中使用动态调用方式,并分析了动态调用的特点、局限性及其解决方案。读者从本文中能够了解 SCA 运行时如何处理动态调用,从而灵活在具体场景中使用 SCA 动态调用。架构师可以使用此信息作为参考,从而设计更为灵活的面向服务的体系结构(Service-Oriented Architecture,SOA)。
引言
SCA 作为一种新的服务组件模型,提供了一种统一的与语言无关的调用方式,从而使客户可以把不同的组件类型,例如 POJO、EJB、业务流程等通过标准的接口来封装和调用。WebSphere Process Server (WPS)将 SCA 作为构建面向服务体系结构(Service Oriented Architecture, SOA)系统的编程模型,提供了基于 SCA 的业务流程管理和系统集成功能。SCA 编程模型中的静态调用方式已被大家所熟识,本文将介绍 SCA 编程模型中的动态调用方式,并以一些简单的例子来说明具体的使用方法。
SCA 动态调用编程模型概述
在 SCA 编程模型中,最基本的组成元素和构建单位就是服务组件。我们在服务组件中实现业务逻辑,并把它组合起来构成一个完整的应用。SCA 编程模型将服务接口与实现分离,每个服务组件通过接口提供给其他服务调用的入口,通过引用来调用其它的服务组件。无论接口还是引用,其调用规范都遵循 WSDL 或 Java 接口。
一个或多个具有内在业务联系的服务组件可以被放置在一个服务模块中,服务模块之间或服务模块与外部系统之间通过导入和导出来进行相互调用。
在传统的静态编程模型中,我们通过连线的方式将引用与提供服务的组件连接起来,从而确定服务组件间的调用关系。但在很多场景下,我们希望能够在运行时再决定被调用的服务组件。这个时候,我们就需要使用 SCA 动态调用模型。
根据被调用的服务组件是否和调用者在同一服务模块内,我们可以将调用的场景分为两类:
-
同一服务模块内的 SCA 动态调用
-
不同服务模块间的 SCA 动态调用
同一服务模块内的 SCA 动态调用
在静态编程模型中,同一服务模块中的 SCA 组件通过连线(Wire)连接,从而确定组件间的调用关系。而在动态编程模型中,我们可以不使用连线,直接选择目标服务进行调用。
在图 1 中,服务组件 Component1 本来被连接到服务组件 Service1,服务组件 Component2 的引用未连接到任何服务组件。通过动态调用模型,我们能够在运行时选择服务组件 Service2 作为服务组件 Component1 所调用的服务,并能灵活选择服务组件 Service1 或 Service2 作为服务组件 Component2 所调用的服务。
图 1. 同一服务模块中的动态调用
不同服务模块间的 SCA 动态调用
在 SCA 编程模型中,服务模块通过服务导出(Export)将服务提供给其它服务模块或外部系统。在静态调用编程模型中,我们只能在服务模块中添加服务导入(Import),并使用连线(Wire)将服务调用者与服务导入连接起来,从而调用其它服务模块中的服务。在动态调用模型中,我们有以下两种调用方式来调用其它服务模块中的服务。
首先,我们可以通过服务导入进行动态调用。在图 2 中,Component1 原本通过 Import 与 Module2 中的 Export1 相连,从而调用 Service1。通过动态调用,我们可以使 Component1 在运行时改为调用 Module3 中的 Export2。在这一场景中,Component1 与 Import,以及 Import 与 Export1 中间的连线并不是必须的,即我们只要有一个与 Component1 上的引用接口一致的服务导入,就可以利用这个服务导入进行动态调用。
图 2. 通过服务导入进行动态调用
其次,我们还可以不经过服务导入直接进行动态调用,这一模式被称为纯动态调用 (Pure Dynamic Invocation)。在图 3 中,Component1 并未与任何服务导入相连接,只需要保证 Component1 上的服务引用与 Export1 和 Export2 的接口一致,我们就可以在运行时通过动态调用方式灵活选择所调用的服务。
图 3. 纯动态调用
如何定义服务地址
SCA 动态调用主要是通过对 WS-Addressing 的支持,将消息寻址信息在运行时传入,从而达到在运行时决定被调用方的动态调用效果,即 SCA 动态调用。我们需要首先了解服务提供者的地址。下面介绍 SCA 中的服务地址定义。动态调用的场景分为服务模块内和不同服务模块间,在这两种场景中,服务地址的定义方式也不同。
同一服务模块内的服务地址定义
对于同一服务模块中的动态调用,服务地址定义的格式为:<moduleName>/<serviceName>
例如:图 1 中的 Service1 的服务地址为 Module1/Service1,Service2 的服务地址为 Module2/Service2。
这里的被调用者可以是服务组件,也可以是服务导入,因此 serviceName 为被调用的服务组件名或服务导入名。
不同服务模块间的服务地址定义
对于不同服务模块间的动态调用,提供服务的模块需要定义服务导出 (Export) 才能被服务调用方调用。根据调用协议的不同,SCA 编程模型对服务导出定义了不同的绑定 (Binding) 类型,而对于不同的绑定种类我们需要采用不同的服务地址定义格式。
SCA 绑定
SCA 绑定的 URI 规则为:sca://<moduleName>/<exportName>
Webservice 绑定
由于 Webservice 绑定支持 SOAP/HTTP 和 SOAP/JMS 这两种方式,Webservice 绑定的 URI 规则也分为两种。
SOAP/HTTP 的 URI 规则为:
http://host:port/<module name >/sca/<export name >
SOAP/JMS 的 URI 规则为:
jms:/queue?destination=<destinationName>&connectionFactory=<factory>&targetservice=<service>
JMS 绑定
JMS 绑定的 URI 规则为:jms:jndi:<qname>?jndiConnectionFactoryName=<cfName>
MQ 绑定
MQ 绑定的 URI 规则为:wmq:/msg/queue/<qname>
HTTP 绑定
HTTP 绑定的 URI 规则为:http://<url>
JCA 绑定
JCA 绑定的 URI 规则为:jca:jndi:<cf_name>
如何进行 SCA 动态调用
有了服务地址的定义,在 SCA 动态调用模型中,我们可以通过 SCA 提供的 EndpointReference API 来进行动态调用,或利用中介流 (Mediation flow) 进行动态调用。
利用 SCA EndpointReference API 进行动态调用
SCA 编程模型中使用 com.ibm.websphere.sca.addressing.EndpointReference 类来描述一个符合 WS-Addressing 规范的端点引用(Endpoint Reference)。我们可以使用 EndpointReferenceFactory 来创建一个 EndpointReference 实例,并设置相应的地址。通过服务调用方组件已有的引用和该 EndpointReference 实例得到的服务对象来调用地址所指定的服务提供方组件。
对于模块内的动态服务调用和模块间的纯动态服务调用,我们可以通过以下代码片断得到一个能够调用服务提供者的服务对象,完成服务调用:
清单 1. 调用服务提供者的服务对象代码
// Reference name
String refName = <ReferenceName>;
// Create an EPR and initialize it
EndpointReference epr =
EndpointReferenceFactory.INSTANCE.createEndpointReference();
epr.setAddress(<EndpointAddress>);
// Get the service passing in reference name and initialized EPR
Service service = (Service) ServiceManager.INSTANCE.getService(refName, epr);
|
对于模块间通过服务导入的动态调用,我们还需要设置导入名称和导入类型:
清单 2. 模块间动态调用相关设置
// Reference name
String refName = <ReferenceName>;
// Create an EPR and initialize it
EndpointReference epr =
EndpointReferenceFactory.INSTANCE.createEndpointReference();
epr.setAddress(<EndpointAddress>);
epr.setBindingType(<BindingType>);
epr.setImport(<ImportName>);
// Get the service passing in reference name and initialized EPR
Service service = (Service) ServiceManager.INSTANCE.getService(refName, epr);
|
需要注意的是,当 refName 定义的引用接口为 Java 接口时,我们可以直接得到一个具有该 Java 接口的服务对象;当 refName 定义的引用接口为 WSDL 接口时,我们只能得到一个 Service 接口的服务对象。
基于中介流的 SCA 动态调用
除了 SCA EndpointReference API,我们还可以利用中介流(Mediation Flow)来完成 SCA 动态调用。在中介流中,所有流转的数据都被封装为 SMO(Service Message Object)。SMO 中的 SMOHeader 包含了 Target 属性和 AlternateTarget 属性,这两个属性都定义为 TargetAddressType,包含了 address、bindingType 和 import 的定义。我们可以通过 Endpoint lookup、Message element setter、XSL transformation、Database lookup 或 custom primitive 来设置这两个属性。中介流在 Callout 节点会根据 SMOHeader 中的 Target 属性与 AlternateTarget 属性动态调用属性中地址所指向的服务。
与 SCA EndpointReference API 类似,对于模块内的动态服务调用和模块间的纯动态服务调用,我们只需要设置 Target 属性和 AlternateTarget 属性的 address 信息。对于模块间通过服务导入的动态调用方式,我们还需要设置 bindingType 和 import 信息。
图 4. SMOHeader 中的 Target 属性与 AlternateTarget 属性
需要注意的是,我们必须在 Callout primitive 中选择 Use dynamic endpoint if set in the message header 选项,否则中介流将不会使用 SCA 动态调用。
图 5. 设置 Callout primitive 以支持 SCA 动态调用
SCA 动态调用中的限制
通过上面的介绍,我们已经对如何进行 SCA 动态调用有了初步的了解。我们只需要对不同的服务提供者定义好各自的服务地址,就可以通过 SCA EndpointReference API 或中介流进行动态调用,从而在运行时灵活选择被调用的服务。下面介绍 SCA 动态调用模型中的一些限制,确保我们能够正确的使用 SCA 动态调用。
纯动态调用对绑定协议的限制
对于纯动态调用模式,只能通过调用 SCA 绑定或 JAX-RPC WebService 绑定的服务导出。如果要调用其他绑定方式的服务导出,我们只能选择通过服务导入来进行动态调用。
纯动态调用对 QoS 的限制
在 SCA 编程模型中,我们通过在接口 (Interface)、引用 (Reference) 和实现 (Implementation) 上添加服务标识 (Qualifier),对 QoS 进行控制。在纯动态调用模式中,调用方与被调用方式间的 QoS 信息无法更改,只能采用默认的 QoS 设置。如果需要在动态调用中自主设置 QoS 信息,例如让被调用方加入调用方的事务,我们也必须采用通过服务导入的动态调用方式,在服务导入上添加需要的 QoS 信息。
结束语
本文介绍了 SCA 编程模型中动态调用方式支持的场景,如何定义服务地址,以及如何通过 SCA EndpointReference API 或中介流来进行动态调用。最后进一步介绍了 SCA 动态调用中对于纯动态调用模式的一些限制。
本文附带的样例程序中包含了利用 SCA EndpointReference API 和中介流进行动态调用的示例。其中 Callee 模块为被调用的服务模块,POJOCaller 模块示范了模块中的动态调用、利用服务导入和未利用服务导入的模块间动态调用。MFCCaller 模块示范了利用中介流进行模块间动态调用。
如果希望对 SCA 动态调用方式有更深入的了解,请参阅附录中的材料。
下载 | 描述 | 名字 | 大小 | 下载方法 |
|---|
| 本文代码示例 | dynamicInvocation.zip | 40 KB | HTTP |
|---|
参考资料 学习
获得产品和技术
关于作者  | |  | 菅骁翔任职于 IBM 中国开发中心,目前从事 WebSphere Process Server 的开发工作。 |
对本文的评价
|