领先一步
VMware 提供培训和认证,助力您的职业发展。
了解更多我们很高兴宣布 '贷款经纪人' 参考实现的第一个部分。'贷款经纪人' 概念已成为展示 企业集成模式 (EIP)(由 Gregor Hohpe 和 Bobby Woolf 撰写)事实上的参考领域,而本次贷款经纪人参考实现的部分展示了如何使用 Spring Integration (SI) 框架实现和应用企业集成模式。
EIP 架构的核心是非常简单但强大的 管道和过滤器 以及 消息 概念。端点(过滤器)通过通道(管道)相互连接。生产端点将消息发送到通道,消息由消费端点检索。此架构旨在定义描述端点之间信息如何交换的各种机制,而无需了解这些端点是什么或它们正在交换什么信息,从而提供了一种非常松散耦合和灵活的协作模型,同时也将集成关注点与业务关注点解耦。EIP 通过进一步定义以下内容扩展了此架构:
Spring Integration (SI) 消息框架旨在提供一个构建在企业集成模式之上的基于 POJO 的编程模型。
提交贷款报价请求 - 消息网关
消息网关模式提供了一种访问消息系统的简单机制,包括我们的贷款经纪人。在 SI 中,您将网关定义为一个普通的 Java 接口 (POJO),无需提供实现,通过 XML 的 <gateway> 元素或通过注解进行配置,并像使用任何其他 Spring bean 一样使用它。SI 将负责通过生成一个消息(负载映射到方法的输入参数)并将其发送到指定通道来委托和映射方法调用到消息基础设施。
LoanBrokerGateway.java 是代表消费者使用的消息网关的接口
网关 XML 配置
<int:gateway id="loanBrokerGateway"
default-request-channel="loanBrokerPreProcessingChannel"
service-interface="org.springframework.integration.loanbroker.LoanBrokerGateway"/>
在上述配置中,无论何时调用 'loanBrokerGateway' bean 上的任何方法,都将构造一个消息并将其发送到 'loanBrokerPreProcessingChannel'。
我们对消息网关的定义 (LoanBrokerGateway.java) 为消费者提供了两种与贷款经纪人互动的方式。消费者可以通过调用 getLoanQuote(loanRequest) 方法请求单个(最佳)报价,或者通过调用 getAllLoanQuotes(loanRequest) 方法请求所有报价。这意味着我们的贷款经纪人必须知道贷款请求的类型。我们还知道有一些预筛查步骤,例如获取和评估消费者的信用评分,仅仅是因为一些高级银行通常只会接受符合最低信用评分要求的消费者的报价请求。
本质上,整个过程就像看医生一样,在看真正的医生之前,您会先见护士,护士会测量您的体温、血压等,并写下医生需要的“元信息”列表。在 EIP 中,一个 消息 是一个简单的结构,由 消息负载 和 消息头 组成。 消息头 是存储与 消息 相关的元信息的好机制。那么我们如何用额外信息丰富我们的消息呢?EIP 定义了 内容丰富器 模式,它描述了如何用额外信息增加一个 消息。Spring Integration 提供了一个 <header-enricher> 元素,允许您快速丰富传输中的消息。但由于我们的贷款经纪人必须在发送报价之前执行几项任务,如果有一个机制可以将流程由一组独立任务组合起来,那就太好了。
组合消息处理器模式描述了围绕构建维护消息流控制的端点的规则,该消息流由多个消息处理器组成。在我们的案例中,预筛查流由3个步骤组成:a) 确定贷款请求的类型; b) 获取消费者的信用历史和评分; c) (根据某些标准)确定通道列表(每个通道对应一个独立的银行)。
Spring Integration 允许您通过 <chain> 元素组合复杂的处理器。
<int:chain id="preScreening" input-channel="loanBrokerPreProcessingChannel" output-channel="banksDistributionChannel">
<int:header-enricher>
<int:header name="RESPONSE_TYPE"
expression="headers.history.iterator().next().attributes['method'].equals('getLoanQuote') ? 'BEST' : 'ALL'" />
</int:header-enricher>
<int:header-enricher>
<int:header name="CREDIT_SCORE" ref="creditBureau" method="getCreditScore"/>
</int:header-enricher>
<int:header-enricher>
<int:header name="BANKS" ref="bankSelector" method="selectBankChannels"/>
</int:header-enricher>
</int:chain>
这将创建一个名为 'preScreening' 的 bean,作为一个 SI 链 端点,它也定义了 输入/输出-通道 来接收和发送消息。上面的 链 由 3 个 header-enricher 处理器组成。第一个将通过使用 SpEL 来访问 消息历史 并根据调用的网关方法确定此头的值来设置 RESPONSE_TYPE 头。
此示例说明了如何使用 SpEL 在确定头值时执行简单的评估,但我们不提倡使用 SpEL 执行复杂的业务逻辑接下来,我们有一个映射到一个处理过程的 header-enricher,该过程负责从信用局(当前是模拟 CreditBureauStub)获取信用评分并设置 CREDIT_SCORE 头。最后一个 header-enricher 使用 BankChannelSelector(参见 bankSelector 配置)。BankChannelSelector.selectBankChannels(..) 方法的实现将消息作为输入,并返回一个 Set<String> 值,包含通道名称,该值将设置为 BANKS 头。这完成了我们的预筛查过程,我们的贷款经纪人现在已准备好通过 banksDistributionChannel 向每个选定的银行发送贷款请求。
BANKS 头定义了动态生成和过滤的通道列表,每个通道都充当代表银行的接收者。我们需要一个允许我们将相同的 消息 发送给所有接收者的端点。
将贷款报价请求分发给选定的银行 - 接收者列表
下面的 XML 配置展示了如何配置此路由器。
<int:router id="bankRecipientListRouter" input-channel="banksDistributionChannel"
expression="headers['BANKS']"
apply-sequence="true"/>
您可以清楚地看到我们是如何通过通道(管道)连接各种端点(过滤器)来组装贷款经纪人,同时传递消息的。您还可以看到我们是通过基于 POJO 的编程技术完成此任务的,几乎没有使用 Spring Integration API(只使用了 BankChannelSelector.java)。SI 负责将我们的 POJO 与消息基础设施对接。贷款经纪人需要做的最后一件事是接收来自银行的贷款报价,按消费者进行聚合(我们不希望将一个消费者的报价显示给另一个消费者),根据消费者的选择标准(单个最佳报价或所有报价)组装回复,并回复给消费者。
聚合贷款报价回复 - 聚合器
聚合器模式描述了一个将相关 消息 分组到一个单一 消息 的端点。可以提供标准和规则来确定 聚合 和 关联 策略。SI 提供了聚合器模式的几种实现以及便捷的基于命名空间的配置。
我们的贷款经纪人通过 <aggregator> 元素定义了一个名为 'loanQuoteAggregator' 的 bean,该元素提供了一个默认的 aggregator 和 correlation 策略。默认的关联策略基于 $corelationId 头关联消息(参见 关联标识符 模式)。有趣的是,我们从未提供此头的值。它是由接收者列表路由器在为每家银行生成一个单独的消息时自动设置的。
消息关联后,它们被释放到实际的聚合器实现。尽管 SI 提供了默认的聚合器,但其策略(收集所有消息的负载列表并用此列表作为负载构建一个新消息)不满足我们的要求。原因是我们的消费者可能需要一个最佳报价或所有报价。为了传达消费者的请求,我们在流程早期设置了 RESPONSE_TYPE 头。现在我们必须评估这个头,并返回所有报价(默认聚合策略将起作用)或最佳报价(默认聚合策略将不起作用,因为我们必须确定哪个贷款报价是最佳的)。
<int:aggregator id="loanQuoteAggregator" input-channel="quotesAggregationChannel" method="aggregateQuotes">
<bean class="org.springframework.integration.loanbroker.LoanQuoteAggregator"/>
</int:aggregator>
显然,选择最佳报价可以基于复杂的标准,并会影响聚合器的复杂性,但目前我们将其保持简单。如果消费者想要最佳报价,我们将选择利率最低的报价。为此,LoanQuoteAggregator.java 将对所有报价进行排序并返回第一个。 LoanQuote.java 实现了 Comparable 接口,该接口根据 rate 属性比较报价。
响应消息创建后,它将被发送到消息网关(以及消费者)的 default-reply-channel,正是该网关启动了整个流程。我们的消费者收到了贷款报价!
需要注意的一件重要事情是,我们没有在 <gateway> 元素上定义 default-reply-channel 属性。事实上,我们没有明确定义任何一个 channel。与其他的消息系统类似,SI 会根据需要自动创建 input 和默认的 reply 通道,这为您提供了另一种进一步简化 Spring Application Context 配置的方式。
在下一期中,我们将通过用这些适配器替换我们的模拟服务来演示 Spring Integration 中可用的各种远程适配器和技术,并将引入与“贷款经纪人”用例相关的异步集成风格。
资源:
'Loan Broker' 参考实现随 Spring Integration 2.0.M3 一同发布(参见下载部分)。它作为一个独立的 Eclipse/Maven 项目分发。您也可以从我们的 Subversion 仓库将其检出。
$> svn co https://src.springframework.org/svn/spring-integration/trunk/spring-integration-samples/loan-broker/ loan-broker $> cd loan-broker $> mvn install
相关链接: Spring Integration Spring Integration in Action 企业集成模式 Spring Integration 入门 (Joshua Long) 敏捷 SOA - 第 1、2 和 3 部分 (Tom McCuch)
感谢 Gary Russel (Spring Source, SI 提交者) 和 Dave Turanski (Spring Source) 为此博客提供的帮助!