级别: 中级 Callum Jackson (callumj@uk.ibm.com), 软件工程师, IBM
Brian Hulse (brian_hulse@uk.ibm.com), 高级软件工程师, IBM
2008 年 4 月 24 日 了解 IBM® WebSphere® Enterprise Service Bus V6.1 的新增功能——聚合。本系列文章包括三个部分,首先向您介绍可用于构建实际场景的基础中介原语,然后描述有用的聚合模式。
引言
WebSphere Enterprise Service Bus V6.1 中介原语 是可重用的构建块,应用程序开发人员可用来构建中介流。本系列的最后一篇文章将说明如何利用实际业务情况从新中介原语构建这些有用的聚合模式。在带您了解使用聚合实现成功中介流所需的重要步骤时将重点介绍模式之间的差异。
不要将聚合看作简单地对消息进行拆分和联接,而应将其看作完整的业务流,包括构成业务流的任何服务调用。在这一方面,本系列文章的第 2 部分将详细讨论新原语之一——服务调用原语的用法。其中包括可用的各种调用类型,以及您可以如何在标准聚合模式中使用它们。为了学习本系列文章,您应该了解为 WebSphere Enterprise Service Bus 开发中介模块的基本知识。
本文讨论 WebSphere Enterprise Service Bus V6.1 中的新聚合功能,并简要介绍服务调用功能。您还可以详细了解创建中介流的过程,包括聚合逻辑。
聚合的强大功能
WebSphere Enterprise Service Bus V6.1 将聚合引入此前需要大量自定义代码的中介流逻辑。在深入技术细节之前,让我们看一下聚合的强大功能以及它为何是重要的企业服务总线 (ESB) 模式。简而言之,入站请求可以映射到若干单独的出站请求。对这些请求的响应可以聚合为原始请求的单个响应。
聚合的可能用法非常广泛而多种多样;一个常见示例是汽车保险报价系统。最终用户使用 Web 界面来提交汽车保险单定价请求,某个业务流程(如 BPEL)执行业务逻辑,然后提交单个报价请求。这时,您可以使用聚合逻辑来查询一组汽车保险公司,然后将结果聚合为单个响应,并传递给业务流程以继续进行处理。在本文的稍后部分将详细介绍该场景的模型示例。
提供聚合支持的中介组件的增强功能
在 WebSphere Enterprise Service Bus V6.1 中为聚合提供的一流支持涉及对中介组件编程模型的几个扩展。这一部分将介绍这些增强功能。
新中介原语
作为 WebSphere Enterprise Service Bus V6.1 中引入的聚合支持的组成部分,实现了三个新原语以及对现有原语的一项增强功能:
- 扇出(Fan Out)
- 扇入(Fan In)
- 服务调用
-
Message Element Setter(已增强)
新扇出原语
您可以使用扇出原语来触发输出末端一次(使用输入消息)或触发输出末端 n 次,其中 n 是已定义重复元素中的项目数。您可以单独使用扇出,或结合使用扇出和扇入。
对于其他中介原语,IBM WebSphere Integration Developer 提供了将属性和末端与原语相关联的工具功能,以提供对聚合行为的自定义。扇出属性视图提供两种触发模式的配置,如图 1 所示。
图 1. 扇出详细信息属性面板
如果选择了重复元素(repeating element)选项,则必须提供 XPath 表达式。XPath 表达式必须 指向在处理扇出原语期间可以遍历的元素数组。对于数组中的每个元素,为存储在扇出上下文中的数组中的选定项触发一条消息,本文的稍后部分将对此进行详细说明。
当您选择 once 选项时,通过连接来自输出末端的多个流来完成聚合,其中每个流都是由消息的一次触发发起的。本文的稍后部分将详细说明其工作原理。
扇出原语具有一个输入末端和三个输出末端,如图 2 所示。
图 2. 扇出中介原语
表 1. 扇出末端
| 末端类型 | 名称 | 描述 |
|---|
| 输入 | In | 此末端接收传入消息,在 once 模式中不加修改地触发。在 iterate 模式下,在触发之前,由 XPath 表达式标识的数组中的元素将被放入扇出上下文中。 |
|---|
| 输出 | Out | 此末端在扇出配置为 once 模式时触发一次,或配置为 iterate 模式时触发 n 次,其中 n 是重复元素的数目。 |
|---|
| 输出 | noOccurrences | 在 iterate 模式下,输入消息不包含任何重复元素的重现时触发此末端。在 once 模式下该末端存在,但从不触发。 |
|---|
| 失败 | fail | 此末端在原语发生意外故障时触发。 |
|---|
新扇入原语
扇入总是与扇出一起出现在相同流中,并作为何时继续执行流的判定点。它接收大量消息,直到到达判定点,此时收到的最后一条消息被传递到输出末端。扇入原语只能与扇出原语结合使用,此规则是通过在 WebSphere Integration Developer 中验证来执行的。
支持三种类型的扇入判定点:
-
Simple count(简单计数):当输入末端收到一定数目的消息时触发输出末端。这不会阻止扇出发送更多的消息,因为扇出计数判定点可能达到不止一次,导致多次触发输出末端。
-
XPath decision(XPath 判定):如果 XPath 表达式对传入消息的计算结果为真,就会触发输出末端。
-
Iterate(遍历):在 iterate 模式下,扇入等待接收由相应扇出原语产生的所有消息;重复元素的所有出现都已遍历。
在 WebSphere Integration Developer 中,扇入原语匹配到单个扇出原语。“Properties”选项卡的“Details”部分显示了相关扇出的配置(以不可编辑格式),以及可用于设置要使用的判定点的配置选项。这对于确保扇入和相应扇出的配置互补很有用。
图 3. 扇入详细信息属性面板
除判定点配置外,还可以设置扇入的超时值。超时期间从关联扇出第一次触发输出末端开始。如果消息在此超时期间之后到达扇入末端,则认为其迟到,并触发 incomplete 末端。默认值为 -1,表示不存在超时,因此没有消息被认为是迟到。
扇入包含两个输入末端和三个输出末端,如表 2 所示。
图 4. 扇入中介原语
表 2. 扇入末端
| 末端类型 | 名称 | 语义 |
|---|
| 输入 | in | 此末端收到的消息被使用,直到到达判定点。 |
|---|
| 输入 | stop | 用户可以连接此末端以显式地阻止扇入操作。到达此末端的消息将导致触发 incomplete 末端;关联的扇出停止触发其输出末端,导致扇出/扇入操作停止。 |
|---|
| 输出 | out | 当扇出/扇入的判定点到达时触发此末端。末端收到的最后一条消息是从此末端触发的,其中包括与该消息关联的共享上下文。 |
|---|
| 输出 | incomplete | 当出现以下情况时触发此末端:消息到达 stop 输入末端;消息到达 in 末端并且超时值已超过;或者当关联扇出已完成处理并且扇入判定点尚未到达时。 |
|---|
| 失败 | fail | 此末端在原语发生意外故障时触发。 |
|---|
新服务调用原语
服务调用原语用于在请求或响应中介流中提出服务请求。服务可以是请求/响应方式或单向方式。在一个流中允许出现服务调用原语的多个实例,从而允许执行一系列服务调用。该原语在概念上与 V6.0.2 中的自定义中介的调用功能相似,但通过三种方式对该功能进行了扩展:
- 由新原语进行的服务调用相对于中介流的执行可以是同步或异步的。
- 增加了重试支持,允许在原语上指定重试计数。运行时支持使用此重试将请求自动重发到响应为故障的服务。可以在“Properties”选项卡的“Retry”部分配置重试设置,其中提供了下列设置:
-
Retry on(重试条件):确定错误响应是否导致重试以及导致重试的方式。提供了下列有效值:
- Never(从不)
- Any fault(任何错误)
-
Unmodeled fault(未建模错误)
-
Modeled fault(建模的错误)
-
Retry count(重试计数):指示在触发故障或超时末端之前,服务调用应重试的次数。
-
Retry delay(重试延迟):设置重试尝试之间的延迟(秒)。
-
Try alternate endpoints(尝试备用端点):可以在服务消息对象 (SMO) 消息头中存储备用端点,从而允许重试逻辑遍历这些备用位置。通过选中相应的复选框来启用该功能,如图 5 所示。
图 5. 服务调用重试面板
自定义中介调用修复了方法签名以包括单个 DataObject 参数(表示 SMO 正文或整个 SMO)。对于方法调用,签名可以是任何内容。这使用户可以调用任何现有服务,而不仅仅是专为从自定义中介调用而设计的服务。
服务调用原语具有单个输入末端和不定数目的输出末端。如果被调用的操作是单向的,则不存在 fault 或 out 末端,因为这两种末端只能存在于双向操作中(请参见图 6)。
图 6. 服务调用原语
表 3. 服务调用末端
| 末端类型 | 名称 | 语义 |
|---|
| 输入 | in | 该末端收到的消息用于形成对操作的调用。 |
|---|
| 输出 | out | 调用的结果用于形成为此末端触发的新消息。如果操作是单向的,则此末端不存在。 |
|---|
| 输出 | 默认为已建模错误名称 | 当服务调用返回相关已建模错误时触发此末端。为操作定义的每个已建模错误都对应一个此类末端。 |
|---|
| 输出 | timeout | 当服务调用由于超时而失败时触发此末端。只有在操作为双向的异步调用中才会触发此末端。如果操作是单向的,则此末端不存在。 |
|---|
| 失败 | fail | 当发生内部错误或调用返回未建模错误时触发此末端。 |
|---|
Message Element Setter 原语增强功能
Message Element Setter 原语已得到增强,为使用 SMO 向数组添加项目提供支持。该功能对于提供聚合支持非常重要,其中可以提交可变数目的多个请求,并且需要存储对这些请求的响应。本系列的第三篇文章将讨论此增强原语的使用模式。
图 7. Message Element Setter 附加功能
附加选项的用法与复制类似。使用 XPath 表达式来选择目标数组(请注意,[ ] 括号未包括在 XPath 表达式中)。类型设置为 append,值为将附加到数组的内容。数组的元素类型和值的类型必须相同。务必认识到,在附加某个值之前,数组的父对象(在上例中为 currentOutlet)必须存在。
为服务消息对象增加的新上下文
典型的聚合场景需要利用特定的消息上下文区域。WebSphere Enterprise Service Bus V6.1 引入了两种新的上下文,以帮助构建这些场景。
共享上下文
WebSphere Enterprise Service Bus V6.0.2 在 SMO 中拥有两个用户定义的数据存储上下文:
- 瞬态上下文(Transient context),用在请求流中,或者用在响应流中。
- 关联上下文(Correlation context),同时用在请求流和响应流中。
在复杂的分支逻辑中,可以拥有这些上下文的两个独立副本,例如,考虑如图 8 所示的流。
图 8. 分支中介流
如果 MessageFilter1 触发两个输出末端,则对输出消息进行克隆,然后发送给 CustomMediation1 的消息是发送给 CustomMediation2 的消息的副本。如果这两个中介将其原语名称附加到关联或瞬态上下文,则每个 Message Logger 原语只能看到与其流分支相关的名称。在典型的聚合场景中,需要具有跨聚合分支存在的数据存储,以允许多个响应聚合到单个响应。该数据存储在 WebSphere Enterprise Service Bus V6.1 中称为共享上下文。现有的上下文(瞬态上下文和关联上下文)仍然可用,并且其工作方式与 V6.0.2 中完全相同。
就像瞬态上下文和关联上下文一样,共享上下文被定义为用户提供的业务对象。在定义了共享上下文之后,就可用于在聚合操作中存储数据。为此,您需要仔细地设计共享上下文业务对象,以确保它适合特定流中的所有聚合场景。
SMO 的共享上下文区域设计用于存储扇出原语和扇入原语之间的聚合数据。具体而言,共享上下文是基于线程的存储区域,在同一线程中共享。共享上下文业务对象的内容在调出调用中不能跨请求流和响应流保持持久,请求流的共享上下文中的任何数据都无法在响应流中重用。因此,您可以仅在特定流中聚合:响应流中的扇入中介不能用于聚合来自请求流中的扇出中介原语的消息。
在扇入原语后,预计在大多数情况下,流对共享上下文中的信息执行映射/转换操作以生成新的 SMO 正文消息类型,或者使用聚合信息来扩展现有类型。您将在本文的稍后部分看到此类型操作的示例。
扇出上下文
当扇出在 iterate 模式下使用时,扇出上下文用于存储重复元素的当前项。扇出上下文包含一个整数字段,其中包含重复元素的 occurrence 的索引,以及包含 occurrence 本身的元素。例如,如果名为 order 的元素有重复元素,则扇出上下文应该与清单 1 所示类似。
清单 1. 扇出上下文的结构
<FanOutContext>
<iteration>0</iteration >
<occurrence>
<order>
…….
</order>
</occurrence>
</FanOutContext>
|
如何创建您的第一个聚合
这一部分将介绍创建包含聚合逻辑的中介组件的过程。该过程基于上文提到的汽车保险报价比较网站用例,并且假设您熟悉 WebSphere Integration Developer 中的应用程序构建的基本概念,特别是中介开发的基本概念。
接下来介绍创建聚合所涉及的步骤:
- 启动 WebSphere Integration Developer 并打开新工作区,然后创建名为
InsuranceQuote 的新中介模块。
- 创建下列四个业务对象,如图 9 所示:
-
Quote:表示中介流以及保险系统的请求消息中的数据
-
QuoteResult:表示来自单一保险系统的组合成一个整体 QuoteResponse 的响应
-
SharedContent:设计以包含来自两个调用的响应
-
QuoteResponse:由中介流返回,在此显示为最终对象
图 9. 业务对象
- 需要定义访问中介和保险报价服务的接口。因此,接下来需要创建如图 10 所示的两个接口。
图 10. 保险接口
- 打开中介模块的 Assembly Diagram,然后将 Quotation 接口拖放到设计图板上。当显示“Component Creation”窗口时,选择 Component with no Implementation Type,然后单击 OK。
- 选择新创建的组件,右键单击该组件,并选择 Rename。将此组件重命名为
InsuranceCompanyA。
- 选择 InsuranceCompanyA 组件,右键单击该组件,然后从菜单中选择 Generate Implementation - Java。
- 当显示“Generate Implementation”窗口时,单击 OK。
- 将显示 Java™ 编辑器,并自动生成存根实现。只需修改
quote 方法:将值 return null; 更改为 return 250.50;。该方法现在应该如清单 2 所示。
清单 2. 存根实现
public Double quote(DataObject quoteDetails)
{
return 250.50;
}
|
- 为
InsuranceCompanyB 服务重复步骤 4 至 8,但是将该组件重命名为 InsuranceCompanyB 而不是 InsuranceCompanyA。
- 将显示 Java 编辑器,并自动生成存根实现。只需修改 quote 方法:将值
return null; 更改为 return 271.60;。该方法现在应如下所示:
清单 3. 存根实现
public Double quote(DataObject quoteDetails)
{
return 271.60;
}
|
- 将 InsuranceQuote 接口拖放到设计图板上。在“Component Creation”窗口中选择 Export with Web Service Binding。然后选择 OK,再次选择 OK(在“Transport Selection”窗口中)。
- 完成以下连接:
- InsuranceQuoteExport1 --> InsuranceQuote
- InsuranceQuote --> InsuranceCompanyA
- InsuranceQuote --> InsuranceCompanyB
其组装关系图应该与图 11 所示类似。
图 11. 组装关系图
- 右键单击中介组件 (InsuranceQuote),并在出现的窗口中选择 Regenerate Implementation(如果出现一个窗口警告已存在该实现,请单击 OK)。
- 在中介流编辑器的最右侧会显示流的上下文类型。单击与 Shared Context 关联的加号。
- 将显示“Data Type Selection”窗口。从列表中选择 SharedContext,并单击 OK。
- 面板位于中介流的左侧。展开 Routing 部分,然后选择 FanOut。将鼠标移动到画布上并单击。这会将
Fan In 原语添加到画布。
- 为以下原语重复上个步骤:
- 扇入原语:在添加该原语时,将显示“Fan Out Primitive Selection”窗口。选择 FanOut1 并单击 OK。
- 服务调用原语:在添加该原语时,将显示“Select Reference Operation”窗口。从“Reference ”部分选择 QuotationPartner 并单击 OK。
- 服务调用原语:在添加该原语时,将显示“Select Reference Operation”窗口。从“Reference”部分选择 QuotationPartner1 并单击 OK。
- 在面板上,展开 Transformation 部分,然后在画布上创建三个 XSL Transformation 和两个 Message Element Setter 原语。
- 将原语放在如下结构中:
图 12. 中介原语
- 完成以下连接:
- Input Node out 末端 -> FanOut1 in 末端
- FanOut1 out 末端 -> XSLTransformation1 in 末端
- FanOut1 out 末端 -> XSLTransformation2 in 末端
- XSLTransformation1 out 末端 -> ServiceInvoke1 in 末端
- XSLTransformation2 out 末端 -> ServiceInvoke2 in 末端
- ServiceInvoke1 out 末端 -> MessageElementSetter1 in 末端
- ServiceInvoke2 out 末端 -> MessageElementSetter2 in 末端
- MessageElementSetter1 out 末端 -> FanIn1 in 末端
- MessageElementSetter2 out 末端 -> FanIn1 in 末端
- FanIn1 out 末端 -> XSLTransformation3 in 末端
- XSLTransformation3 out 末端 -> InputResponse in 末端
中介流应该与图 13 所示类似。
图 13. 中介流
- 已将所有必要原语添加到设计图板中。需要修改一些默认配置。首先选择 XSLTransformation1 原语,然后在“Properties”选项卡中选择 Details 部分。
- 将显示关于缺少映射文件的错误消息。选择 New 按钮,然后在“New XML Mapping”窗口中单击 Finish。
- 将显示新 XSLT 编辑器。使用匹配映射按钮自动地创建所需的映射。创建了内联映射。保存映射文件。
- 为 XSLTranformation2 原语重复上述步骤。
- 选择 MessageElementSetter1 原语。在“Properties”窗格中选择 Details。单击 Add,然后如图 14 所示在新窗口中填写值。
图 14. 存储公司名称
- 单击 Finish。同样,使用如图 15 所示的值创建第二个属性。
图 15. 存储保险报价
“Details”部分应包含两个条目。
- 为
MessageElementSetter2 重复此过程,并使用 CompanyB 代替 CompanyA(参见图 16)。
图 16. 存储 CompanyB 报价数据
- 对于 XSLTransformation3,在“Properties”选项卡的“Details”部分单击 New。然后在“New XML Mapping”窗口中选择 Next。
- 将“Message Root”更改为 / 来代替默认的 /body,然后单击 Finish。
- 在 XSLT 编辑器中单击 Map source and target based on name and types 按钮。这会自动为转换生成默认连接。
- 导航回顶级目录,然后创建下列连接:
- /smo/context/shared/companyA --> /body/quoteResponse/quoteResults/quoteResponses
- /smo/context/shared/companyB --> /body/quoteResponse/quoteResults/quoteResponses
每个 Inline map 操作符都会有一个小的注释标记 (!),因为目标是数组并需要索引。因此,选择每个 Inline 操作符(每次一个,companyA 之后是 companyB)。在“Properties”窗格中选择 Cardinality 部分,然后分别为索引填写 1 和 2(参见图 17)。
图 17. 转换到响应消息
- 选择与
companyA 内联映射关联的黄色向下箭头,然后在映射内创建下列映射(参见图 18):
- companyA/Company --> quoteResponses/Company
- companyA/Cost --> quoteResponses/Cost
图 18. 响应转换内的报价映射
- 为
companyB 内联映射重复相同的过程,然后保存映射文件。
- 返回中介流编辑器,并在“Properties”选项卡中选择 FanIn1 原语。将“input messages have been received”字段的值从
1 更改为 2,如图 19 所示。
图 19. 扇入属性面板
- 保存中介流 (Ctrl+S)。
- 启动内置的 WebSphere Enterprise Service Bus 或 IBM WebSphere Process Server 测试环境,然后部署 InsuranceQuoteApp 应用程序。
- 在组装关系图中选择 InsuranceQuote 组件并右键单击。从菜单中选择 Test Component。
- 为不包含默认值的参数填写一些合理的值,如表 4 所示。
表 4. 非默认属性
| 参数名 | 参数值 |
|---|
| Name | Bob |
|---|
| House number | 123 |
|---|
| Postcode | AK12 5RE |
|---|
| City | Manchester |
|---|
| LicenseType | Full |
|---|
| CarReg | A1234567 |
|---|
- 单击 Continue。
- 将收到包含两个保险报价的响应。
结束语
本文讨论了作为 WebSphere Enterprise Service Bus V6.1 的一部分引入的中介原语,可用于在中介模块中创建聚合场景。我们探讨了各个原语的输入、输出和失败末端,以及原语的操作模式。现在您应该了解了这些原语的工作方式,并了解了如何在简单聚合场景中使用它们。
参考资料 学习
获得产品和技术
讨论
作者简介  | 
|  | Callum Jackson 是位于英国赫斯利的 WebSphere 企业服务总线部门的一名软件工程师,他从 2005 年开始从事产品领域的工作。此前他在 ISSW 从事电信行业的 SOA 应用程序开发工作。 |
 | 
|  | Brian Hulse 是位于英国赫斯利的 WebSphere 企业服务总线部门的一名高级软件工程师。他在赫斯利从事软件开发已有 20 年时间,其中最后 5 年在 SOA 领域工作。 |
对本文的评价
|