从 Spring Integration 2.0 开始,Spring Integration 发行版不再包含示例。 取而代之的是,我们转向了一种更简单的协作模式,这种模式应该促进更好的社区参与,理想情况下,更多的贡献。 示例现在具有专用的 GitHub 存储库。 示例开发也有自己的生命周期,它不依赖于框架版本的生命周期,尽管出于兼容性原因,存储库仍会标记每个主要版本。
对社区的最大好处是,我们现在可以添加更多示例并立即提供给您,而无需等待下一个版本。 拥有自己的 GitHub 存储库,不与实际框架绑定,这也是一个很大的好处。 现在,您有一个专门的地方来建议示例以及报告现有示例的问题。 您也可以将示例作为拉取请求提交给我们。 如果我们认为您的样本增加了价值,我们将非常乐意将其添加到“样本”存储库中,并适当地将您视为作者。
从哪里获得样品
Spring Integration Samples 项目托管在 GitHub 上。 为了签出或克隆示例,必须在系统上安装 Git 客户端。 有许多平台(例如用于 Eclipse IDE 的 EGit)提供了几种基于 GUI 的产品。 一个简单的谷歌搜索可以帮助你找到它们。 您还可以使用 Git 的命令行界面。
如果您需要有关如何安装或使用 Git 的更多信息,请访问:https://git-scm.com/。 |
要使用 Git 命令行工具克隆(签出)Spring Integration 示例存储库,请发出以下命令:
$ git clone https://github.com/spring-projects/spring-integration-samples.git
上述命令将整个示例存储库克隆到您发出该命令的工作目录中命名的目录中。
由于示例存储库是实时存储库,因此可能需要执行定期拉取(更新)以获取新示例和现有示例的更新。
为此,请发出以下命令:spring-integration-samples
git
git pull
$ git pull
如果您需要有关如何安装或使用 Git 的更多信息,请访问:https://git-scm.com/。 |
提交样品或样品请求
您可以提交新样品和样品请求。 我们非常感谢任何改进样本的努力,包括分享好的想法。
我怎样才能贡献自己的样本?
GitHub 用于社交编码:如果您想将自己的代码示例提交到 Spring Integration Samples 项目,我们鼓励通过来自此存储库的分支的拉取请求来做出贡献。 如果要以这种方式贡献代码,请尽可能引用 GutHub 问题,该问题提供有关示例的一些详细信息。
签署贡献者许可协议
非常重要:在我们接受您的 Spring Integration 示例之前,我们需要您签署 SpringSource 贡献者许可协议 (CLA)。 签署贡献者协议不会授予任何人对主存储库的提交权限,但这确实意味着我们可以接受您的贡献,如果我们这样做,您将获得作者信用。 要阅读并签署 CLA,请转到: 从“项目”下拉列表中,选择“Spring Integration”。 项目负责人是Artem Bilan。 |
代码贡献流程
有关实际的代码贡献过程,请阅读 Spring 集成的贡献者指南。 他们也申请了样品项目。 您可以在 github.com/spring-projects/spring-integration/blob/main/CONTRIBUTING.adoc 找到它们
此过程可确保每个提交都经过同行评审。 事实上,核心提交者遵循完全相同的规则。 我们非常感谢您的Spring Integration示例!
样品请求
如前所述,Spring Integration Samples 项目使用 GitHub issue 作为 bug 跟踪系统。 要提交新的样品请求,请访问 github.com/spring-projects/spring-integration-samples/issues。
签署贡献者许可协议
非常重要:在我们接受您的 Spring Integration 示例之前,我们需要您签署 SpringSource 贡献者许可协议 (CLA)。 签署贡献者协议不会授予任何人对主存储库的提交权限,但这确实意味着我们可以接受您的贡献,如果我们这样做,您将获得作者信用。 要阅读并签署 CLA,请转到: 从“项目”下拉列表中,选择“Spring Integration”。 项目负责人是Artem Bilan。 |
示例结构
从 Spring Integration 2.0 开始,示例的结构发生了变化。 随着更多样本的计划,我们意识到并非所有样本都有相同的目标。 它们都有一个共同的目标,即向您展示如何应用和使用 Spring Integration 框架。 但是,它们的不同之处在于,一些示例专注于技术用例,而另一些则侧重于业务用例。 此外,一些示例还展示了可用于解决某些方案(技术和业务)的各种技术。 新的样品分类使我们能够根据每个样品解决的问题更好地组织它们,同时为您提供一种更简单的方法来找到适合您需求的样品。
目前,有四个类别。 在示例存储库中,每个类别都有自己的目录,该目录以类别名称命名:
- 基本 (
samples/basic
) -
这是一个很好的起点。 此处的示例是出于技术动机,并演示了有关配置和代码的最低限度。 这些应该通过向您介绍Spring Integration的基本概念,API和配置以及企业集成模式(EIP)来帮助您快速入门。 例如,如果您正在寻找有关如何实现服务激活器并将其连接到消息通道的答案,如何使用消息传递网关作为消息交换的门面,或者如何开始使用 MAIL、TCP/UDP 或其他模块,那么这里是查找优质示例的正确位置。 最重要的是,这是一个很好的起点。
samples/basic
- 中级 (
samples/intermediate
) -
此类别针对的是已经熟悉 Spring 集成框架(除了入门之外)但在解决切换到消息传递架构后可能遇到的更高级技术问题时需要更多指导的开发人员。 例如,如果您正在寻找有关如何处理各种消息交换方案中的错误或如何正确配置聚合器以应对某些消息从未到达进行聚合的情况的答案,或者超出特定组件的基本实现和配置并暴露“其他”类型的问题的任何其他问题, 这是查找此类样本的正确位置。
- 高级 (
samples/advanced
) -
此类别针对的是非常熟悉 Spring Integration 框架但希望通过使用 Spring Integration 的公共 API 来扩展它以满足特定自定义需求的开发人员。 例如,如果您正在寻找展示如何实现自定义通道或消费者(基于事件或基于轮询)的示例,或者您正在尝试找出在 Spring Integration Bean 解析器层次结构之上实现自定义 Bean 解析器的最合适方法(也许在为自定义组件实现您自己的命名空间和架构时), 这是寻找的正确地方。 在这里,您还可以找到有助于您进行适配器开发的示例。 Spring Integration 附带了一个广泛的适配器库,可让您将远程系统与 Spring Integration 消息传递框架连接起来。 但是,您可能需要与核心框架未提供适配器的系统集成。 如果是这样,您可能会决定实现自己的(请考虑贡献它)。 此类别将包括向您展示如何操作的示例。
- 应用 (
samples/applications
) -
此类别针对的是那些对消息驱动架构和 EIP 有很好的理解,并且对 Spring 和 Spring Integration 的理解高于平均水平的开发人员和架构师,他们正在寻找解决特定业务问题的示例。 换句话说,此类别中示例的重点是业务用例,以及如何通过消息驱动的架构,特别是Spring Integration来解决这些问题。 例如,如果您想了解如何使用 Spring Integration 实现和自动化贷款经纪人或旅行社流程,那么这里是查找这些类型示例的正确位置。
Spring Integration 是一个社区驱动的框架。 因此,社区参与很重要。 这包括样品。 如果您找不到您要找的东西,请告诉我们! |
Spring Integration 是一个社区驱动的框架。 因此,社区参与很重要。 这包括样品。 如果您找不到您要找的东西,请告诉我们! |
样品
目前,Spring Integration 附带了相当多的示例,您只能期待更多。
为了帮助您更好地浏览它们,每个示例都附带了自己的文件,其中涵盖了有关示例的几个详细信息(例如,它解决了哪些 EIP 模式、它尝试解决的问题、如何运行示例以及其他详细信息)。
但是,某些示例需要更详细的,有时是图形化的解释。
在本节中,您可以找到我们认为需要特别注意的样品的详细信息。readme.txt
贷款经纪人
本节介绍 Spring Integration 示例中包含的贷款代理示例应用程序。 此示例的灵感来自 Gregor Hohpe 和 Bobby Woolf 的《企业集成模式》一书中介绍的一个示例。
下图显示了整个过程:

EIP 架构的核心是管道、过滤器,当然还有消息等非常简单但功能强大的概念。 端点(过滤器)通过通道(管道)相互连接。 生产终结点将消息发送到通道,使用终结点检索消息。 此体系结构旨在定义各种机制,这些机制描述如何在端点之间交换信息,而不知道这些端点是什么或它们正在交换什么信息。 因此,它提供了一个非常松散耦合和灵活的协作模型,同时也将集成问题与业务问题分离。 EIP 通过进一步定义以下内容来扩展此架构:
-
管道的类型(点对点通道、发布-订阅通道、通道适配器等)
-
围绕过滤器如何与管道协作的核心过滤器和模式(消息路由器、拆分器和聚合器、各种消息转换模式等)
EIP 书的第 9 章很好地描述了此用例的细节和变化,但以下是简要摘要: 在购买最佳贷款报价时,消费者订阅了贷款经纪人的服务,该经纪人处理以下详细信息:
-
消费者预筛选(例如,获取和审查消费者的信用记录)
-
确定最合适的银行(例如,根据消费者的信用记录或评分)
-
向每家选定银行发送贷款报价请求
-
收集每家银行的回复
-
根据消费者的要求过滤回复并确定最佳报价。
-
将贷款报价传回给消费者。
获得贷款报价的实际过程通常要复杂一些。 但是,由于我们的目标是演示如何在 Spring Integration 中实现和实现企业集成模式,因此用例已被简化为仅专注于流程的集成方面。 这并不是试图为您提供有关消费者财务的建议。
通过聘请贷款经纪人,消费者与贷款经纪人的运营细节隔离开来,每个贷款经纪人的运营可能会相互推迟以保持竞争优势,因此无论我们组装和实施什么,都必须是灵活的,以便可以快速轻松地引入任何变化。
贷款经纪人样本实际上并没有与任何“想象中的”银行或征信机构交谈。 这些服务被存根了。 |
我们的目标是从整体上组装、编排和测试流程的集成方面。 只有这样,我们才能开始考虑将这些流程连接到实际服务中。 届时,无论特定贷款经纪人与之交易的银行数量或用于与这些银行通信的通信媒体(或协议)类型(JMS、WS、TCP 等)如何,组装过程及其配置都不会更改。
设计
在分析前面列出的六个要求时,您可以看到它们都是集成问题。 例如,在消费者预筛选步骤中,我们需要收集有关消费者和消费者愿望的额外信息,并用额外的元信息丰富贷款请求。 然后,我们必须过滤这些信息以选择最合适的银行列表,依此类推。 扩充、筛选和选择都是 EIP 以模式形式定义解决方案的集成问题。 Spring Integration 提供了这些模式的实现。
下图显示了邮件网关的表示形式:

消息传递网关模式提供了一种访问消息传递系统(包括我们的贷款经纪人)的简单机制。
在 Spring Integration 中,您可以将网关定义为普通的旧 Java 接口(无需提供实现),使用 XML 元素或 Java 中的注释对其进行配置,并像使用任何其他 Spring Bean 一样使用它。
Spring Integration 通过生成消息(有效负载映射到方法的输入参数)并将其发送到指定通道,负责将方法调用委托和映射到消息传递基础设施。
下面的示例演示如何使用 XML 定义此类网关:<gateway>
<int:gateway id="loanBrokerGateway"
default-request-channel="loanBrokerPreProcessingChannel"
service-interface="org.springframework.integration.samples.loanbroker.LoanBrokerGateway">
<int:method name="getBestLoanQuote">
<int:header name="RESPONSE_TYPE" value="BEST"/>
</int:method>
</int:gateway>
我们当前的网关提供了两种可以调用的方法。
一个返回最佳单引号,另一个返回所有引号。
不知何故,在下游,我们需要知道呼叫者需要什么类型的回复。
在消息传递体系结构中实现这一点的最佳方法是使用一些描述您的意图的元数据来丰富消息的内容。
Content Enricher 是解决此问题的模式之一。
为了方便起见,Spring Integration确实提供了一个单独的配置元素,以使用任意数据丰富消息头(稍后介绍)
但是,由于该元素负责构造初始消息,因此它包括使用任意消息标头扩充新创建的消息的功能。
在我们的示例中,我们添加一个标头,其值为每当调用该方法时。
对于其他方法,我们不添加任何标头。
现在我们可以检查下游是否存在此标头。
根据它的存在和价值,我们可以确定呼叫者想要什么类型的回复。gateway
RESPONSE_TYPE
BEST
getBestQuote()
根据用例,我们还知道需要执行一些预筛选步骤,例如获取和评估消费者的信用评分,因为一些首屈一指的银行只接受满足最低信用评分要求的消费者的报价请求。 因此,如果消息在转发给银行之前能用这些信息来丰富,那就太好了。 如果当需要完成几个过程来提供这种元信息时,可以将这些过程分组到一个单元中,那就太好了。 在我们的用例中,我们需要确定信用评分,并根据信用评分和一些规则,选择要向其发送报价请求的消息通道(银行通道)列表。
组合消息处理器
组合消息处理器模式描述了有关构建端点的规则,这些端点保持对消息流(由多个消息处理器组成)的控制。
在 Spring Integration 中,组合的消息处理器模式由元素实现。<chain>
下图显示了链式模式:

上图显示,我们有一个带有内部 header-enricher 元素的链,该元素使用标头和值(由对信用服务的调用确定)进一步丰富消息的内容,这是一个由“creditBureau”名称标识的简单 POJO spring bean)。
然后,它委托给消息路由器。CREDIT_SCORE
下图显示了消息路由器模式:

Spring Integration 提供了消息路由模式的多种实现。
在本例中,我们使用一个路由器,该路由器根据评估表达式(在 Spring 表达式语言中)来确定通道列表,该表达式查看信用评分(在上一步中确定),并根据信用评分的值从 Bean 中选择其值为 或 的通道列表。
选择通道列表后,消息将路由到这些通道。Map
id
banks
premier
secondary
现在,贷款经纪人需要做的最后一件事是接收银行的贷款报价,按消费者汇总(我们不想显示从一个消费者到另一个消费者的报价),根据消费者的选择标准(单个最佳报价或所有报价)收集响应,并将回复发送给消费者。
下图显示了消息聚合器模式:

聚合器模式描述了将相关消息分组为单个消息的终结点。 可以提供标准和规则来确定聚合和关联策略。 Spring Integration 提供了聚合器模式的多种实现,以及方便的基于命名空间的配置。
以下示例演示如何定义聚合器:
<int:aggregator id="quotesAggregator"
input-channel="quotesAggregationChannel"
method="aggregateQuotes">
<beans:bean class="org.springframework.integration.samples.loanbroker.LoanQuoteAggregator"/>
</int:aggregator>
我们的贷款经纪人定义了一个带有该元素的“quotesAggregator”bean,它提供了一个默认的聚合和关联策略。
默认关联策略基于标头关联消息(请参阅 EIP 手册中的关联标识符模式)。
请注意,我们从未提供此标头的值。
路由器在为每个银行通道生成单独的消息时,会自动设置它。<aggregator>
correlationId
一旦消息被关联,它们就会被释放到实际的聚合器实现中。
尽管 Spring Integration 提供了一个默认的聚合器,但它的策略(从所有消息中收集有效负载列表并使用此列表作为其有效负载构建新消息)并不能满足我们的要求。
在消息中包含所有结果是一个问题,因为我们的消费者可能需要一个最佳报价或所有报价。
为了传达消费者的意图,在流程的早期,我们设置了标题。
现在我们必须评估这个标头并返回所有报价(默认聚合策略有效)或最佳报价(默认聚合策略不起作用,因为我们必须确定哪个贷款报价是最好的)。RESPONSE_TYPE
在更现实的应用程序中,选择最佳报价可能基于复杂的条件,这些条件可能会影响聚合器实现和配置的复杂性。
不过,就目前而言,我们正在让它变得简单。
如果消费者想要最好的报价,我们会选择利率最低的报价。
为此,该类按利率对所有报价进行排序,并返回第一个报价。
该类实现以根据 rate 属性比较报价。
创建响应消息后,将将其发送到启动该过程的消息传递网关的默认应答通道(从而发送到使用者)。
我们的消费者收到了贷款报价!LoanQuoteAggregator
LoanQuote
Comparable
总之,基于POJO(即现有或遗留)逻辑和轻量级、可嵌入的消息传递框架(Spring Integration)组装了一个相当复杂的过程,该框架具有松散耦合的编程模型,旨在简化异构系统的集成,而无需重量级的类似ESB的引擎或专有的开发和部署环境。 作为开发人员,您不需要仅仅因为有集成问题就将 Swing 或基于控制台的应用程序移植到类似 ESB 的服务器或实现专有接口。
此示例和本节中的其他示例是建立在 Enterprise Integration Patterns 之上的。 您可以将它们视为解决方案的“构建基块”。 它们不是完整的解决方案。 集成问题存在于所有类型的应用程序(无论是否基于服务器)中。 我们的目标是使集成应用程序不需要更改设计、测试和部署策略。
The Cafe 样品
本节介绍 Spring Integration 示例中包含的 café 示例应用程序。 此示例的灵感来自 Gregor Hohpe 的 Ramblings 中的另一个示例。
域是咖啡馆的域,下图描述了基本流程:

该对象可以包含多个 .
下订单后,拆分器会将复合订单消息分解为每杯饮料的一条消息。
然后,路由器会处理其中的每一个,该路由器确定饮料是热的还是冷的(通过检查对象的“isIced”属性)。
准备每种饮料,但冷热饮料的准备通过两种不同的方法处理:“prepareHotDrink”和“prepareColdDrink”。
然后将准备好的饮料发送到汇总到一个对象的地方。Order
OrderItems
OrderItem
Barista
Waiter
Delivery
以下列表显示了 XML 配置:
<?xml version="1.0" encoding="UTF-8"?>
<beans:beans xmlns:int="http://www.springframework.org/schema/integration"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:beans="http://www.springframework.org/schema/beans"
xmlns:int-stream="http://www.springframework.org/schema/integration/stream"
xsi:schemaLocation="http://www.springframework.org/schema/beans
https://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/integration
https://www.springframework.org/schema/integration/spring-integration.xsd
http://www.springframework.org/schema/integration/stream
https://www.springframework.org/schema/integration/stream/spring-integration-stream.xsd">
<int:gateway id="cafe" service-interface="o.s.i.samples.cafe.Cafe"/>
<int:channel id="orders"/>
<int:splitter input-channel="orders" ref="orderSplitter"
method="split" output-channel="drinks"/>
<int:channel id="drinks"/>
<int:router input-channel="drinks"
ref="drinkRouter" method="resolveOrderItemChannel"/>
<int:channel id="coldDrinks"><int:queue capacity="10"/></int:channel>
<int:service-activator input-channel="coldDrinks" ref="barista"
method="prepareColdDrink" output-channel="preparedDrinks"/>
<int:channel id="hotDrinks"><int:queue capacity="10"/></int:channel>
<int:service-activator input-channel="hotDrinks" ref="barista"
method="prepareHotDrink" output-channel="preparedDrinks"/>
<int:channel id="preparedDrinks"/>
<int:aggregator input-channel="preparedDrinks" ref="waiter"
method="prepareDelivery" output-channel="deliveries"/>
<int-stream:stdout-channel-adapter id="deliveries"/>
<beans:bean id="orderSplitter"
class="org.springframework.integration.samples.cafe.xml.OrderSplitter"/>
<beans:bean id="drinkRouter"
class="org.springframework.integration.samples.cafe.xml.DrinkRouter"/>
<beans:bean id="barista" class="o.s.i.samples.cafe.xml.Barista"/>
<beans:bean id="waiter" class="o.s.i.samples.cafe.xml.Waiter"/>
<int:poller id="poller" default="true" fixed-rate="1000"/>
</beans:beans>
每个消息端点都连接到输入通道和/或输出通道。
每个端点管理自己的生命周期(默认情况下,端点在初始化时自动启动,为防止这种情况,请添加值为 的属性)。
最重要的是,请注意,这些对象是具有强类型方法参数的简单 POJO。
以下示例显示了拆分器:auto-startup
false
public class OrderSplitter {
public List<OrderItem> split(Order order) {
return order.getItems();
}
}
对于路由器,返回值不必是实例(尽管它可以是)。
在此示例中,将改为返回保存通道名称的值,如以下列表所示。MessageChannel
String
public class DrinkRouter {
public String resolveOrderItemChannel(OrderItem orderItem) {
return (orderItem.isIced()) ? "coldDrinks" : "hotDrinks";
}
}
现在,回到 XML,您可以看到有两个元素。
其中每个都委托给同一个实例,但使用不同的方法( 或 ),每个方法对应于已路由订单项的两个通道之一。
下面的列表显示了 Barista 类(其中包含 和 方法)<service-activator>
Barista
prepareHotDrink
prepareColdDrink
prepareHotDrink
prepareColdDrink
public class Barista {
private long hotDrinkDelay = 5000;
private long coldDrinkDelay = 1000;
private AtomicInteger hotDrinkCounter = new AtomicInteger();
private AtomicInteger coldDrinkCounter = new AtomicInteger();
public void setHotDrinkDelay(long hotDrinkDelay) {
this.hotDrinkDelay = hotDrinkDelay;
}
public void setColdDrinkDelay(long coldDrinkDelay) {
this.coldDrinkDelay = coldDrinkDelay;
}
public Drink prepareHotDrink(OrderItem orderItem) {
try {
Thread.sleep(this.hotDrinkDelay);
System.out.println(Thread.currentThread().getName()
+ " prepared hot drink #" + hotDrinkCounter.incrementAndGet()
+ " for order #" + orderItem.getOrder().getNumber()
+ ": " + orderItem);
return new Drink(orderItem.getOrder().getNumber(), orderItem.getDrinkType(),
orderItem.isIced(), orderItem.getShots());
}
catch (InterruptedException e) {
Thread.currentThread().interrupt();
return null;
}
}
public Drink prepareColdDrink(OrderItem orderItem) {
try {
Thread.sleep(this.coldDrinkDelay);
System.out.println(Thread.currentThread().getName()
+ " prepared cold drink #" + coldDrinkCounter.incrementAndGet()
+ " for order #" + orderItem.getOrder().getNumber() + ": "
+ orderItem);
return new Drink(orderItem.getOrder().getNumber(), orderItem.getDrinkType(),
orderItem.isIced(), orderItem.getShots());
}
catch (InterruptedException e) {
Thread.currentThread().interrupt();
return null;
}
}
}
从前面的代码摘录中可以看出,这些方法具有不同的延迟(热饮的准备时间是其五倍)。
这模拟了以不同速率完成的工作。
当“main”方法运行时,它会循环 100 次,每次发送一杯热饮和一杯冷饮。
它实际上通过调用接口上的“placeOrder”方法来发送消息。
在前面的 XML 配置中,您可以看到指定了该元素。
这将触发实现给定服务接口并将其连接到通道的代理的创建。
通道名称在接口的注释中提供,如以下接口定义所示:Barista
CafeDemo
Cafe
<gateway>
@Gateway
Cafe
public interface Cafe {
@Gateway(requestChannel="orders")
void placeOrder(Order order);
}
最后,看一下本身的方法:main()
CafeDemo
public static void main(String[] args) {
AbstractApplicationContext context = null;
if (args.length > 0) {
context = new FileSystemXmlApplicationContext(args);
}
else {
context = new ClassPathXmlApplicationContext("cafeDemo.xml", CafeDemo.class);
}
Cafe cafe = context.getBean("cafe", Cafe.class);
for (int i = 1; i <= 100; i++) {
Order order = new Order(i);
order.addItem(DrinkType.LATTE, 2, false);
order.addItem(DrinkType.MOCHA, 3, true);
cafe.placeOrder(order);
}
}
要运行此示例以及其他八个示例,请参阅主发行版的目录(如本章开头所述)。README.txt samples |
当你跑步时,你可以看到冷饮的初始准备速度比热饮快。
因为有一个聚合器,冷饮有效地受到热饮准备速度的限制。
这是可以预料的,基于它们各自的 1000 和 5000 毫秒的延迟。
但是,通过使用并发任务执行器配置轮询器,可以显著改变结果。
例如,您可以为热饮咖啡师使用具有五个工作人员的线程池执行器,同时保持冷饮咖啡师的原样。
以下列表配置了这样的安排:cafeDemo
<int:service-activator input-channel="hotDrinks"
ref="barista"
method="prepareHotDrink"
output-channel="preparedDrinks"/>
<int:service-activator input-channel="hotDrinks"
ref="barista"
method="prepareHotDrink"
output-channel="preparedDrinks">
<int:poller task-executor="pool" fixed-rate="1000"/>
</int:service-activator>
<task:executor id="pool" pool-size="5"/>
另请注意,工作线程名称随每次调用一起显示。 您可以看到热饮是由任务执行器线程准备的。 如果提供更短的轮询器间隔(如 100 毫秒),则可以看到它偶尔会通过强制任务计划程序(调用方)调用操作来限制输入。
除了试验轮询器的并发设置外,还可以添加“事务”子元素,然后引用上下文中的任何实例。PlatformTransactionManager |
XML 消息传递示例
中的 XML 消息传递示例演示如何使用一些提供的处理 XML 有效负载的组件。
此示例使用处理以 XML 表示的书籍的订单的想法。basic/xml
此示例演示命名空间前缀可以是所需的任何内容。
虽然我们通常使用,但对于集成 XML 组件,示例使用 .
(是“Integration”的缩写,也是“Spring Integration”的缩写。int-xml si-xml int si |
首先,将订单拆分为多条消息,每条消息表示 XPath 拆分器组件中的单个订单项。 以下列表显示了拆分器的配置:
<si-xml:xpath-splitter id="orderItemSplitter" input-channel="ordersChannel"
output-channel="stockCheckerChannel" create-documents="true">
<si-xml:xpath-expression expression="/orderNs:order/orderNs:orderItem"
namespace-map="orderNamespaceMap" />
</si-xml:xpath-splitter>
然后,服务激活器将消息传递到库存检查器 POJO 中。
订单物料文档使用来自库存检查器的有关订单物料库存水平的信息进行扩充。
然后,此扩充的订单项消息用于路由消息。
如果订单物料有库存,则消息将路由到仓库。
以下列表配置路由消息:xpath-router
<si-xml:xpath-router id="inStockRouter" input-channel="orderRoutingChannel" resolution-required="true">
<si-xml:xpath-expression expression="/orderNs:orderItem/@in-stock" namespace-map="orderNamespaceMap" />
<si-xml:mapping value="true" channel="warehouseDispatchChannel"/>
<si-xml:mapping value="false" channel="outOfStockChannel"/>
</si-xml:xpath-router>
当订单物料没有库存时,使用 XSLT 将消息转换为适合发送给供应商的格式。 以下清单配置 XSLT 转换器:
<si-xml:xslt-transformer input-channel="outOfStockChannel"
output-channel="resupplyOrderChannel"
xsl-resource="classpath:org/springframework/integration/samples/xml/bigBooksSupplierTransformer.xsl"/>
贷款经纪人样本实际上并没有与任何“想象中的”银行或征信机构交谈。 这些服务被存根了。 |
要运行此示例以及其他八个示例,请参阅主发行版的目录(如本章开头所述)。README.txt samples |
除了试验轮询器的并发设置外,还可以添加“事务”子元素,然后引用上下文中的任何实例。PlatformTransactionManager |
此示例演示命名空间前缀可以是所需的任何内容。
虽然我们通常使用,但对于集成 XML 组件,示例使用 .
(是“Integration”的缩写,也是“Spring Integration”的缩写。int-xml si-xml int si |