领先一步
VMware 提供培训和认证,助您加速进步。
了解更多我们很高兴地宣布 Spring Integration 2.0 的第一个候选版本!下载 | 参考手册 | JavaDoc
我想借此机会提供一个通用的“有什么新内容?”指南。实际上,新的功能和改进太多,无法在一篇文章中全部涵盖,但我将重点介绍一些亮点。随着我们越来越接近 2.0 GA 版本,我们将发布更多博客。目前,本文大致基于 Oleg 和我上周在 SpringOne 上的一次演示。该演示主要是通过代码演示的,代码可在我们的Git 仓库中找到。
为了提供一些结构,我将按几个类别介绍这些功能……
Spring Integration 2.0 直接构建在 Spring 3.0 之上。事实上,RC1 版本是基于上周发布的 Spring 3.0.5 构建的。在这里,我们将介绍底层框架的这一重要升级所带来的几个最值得注意的功能。
现在,您可以在 Spring Integration 核心命名空间中的 transformer、router、filter、splitter、aggregator、service-activator 以及更多元素中使用 SpEL 表达式。例如,如果您可以基于载荷对象中的简单属性评估 Filter 规则,只需执行以下操作:
<filter input-channel="numbers" expression="payload > 0" output-channel="positives"/>
在许多情况下,'expression' 属性可以取代 'ref' 和 'method' 以及 ref 指向的 POJO。另一方面,即使您需要执行 Spring 上下文中某个 bean 的方法,简单的 'method' 属性可能也不够。例如,您可能需要控制传递给方法的参数不止一个。虽然方法参数上的 @Payload 和 @Header 注释提供了一种选择,但有时最好将这些细节保留在配置中而不是代码中。以下是一个使用 SpEL BeanResolver 策略而不是 'ref' 的示例:
<router input-channel="accounts"
expression="@accountService.getAccountType(payload.accountId, payload.address.country)"/>
您可以定义一个名为 "integrationConversionService" 的 ConversionService bean,然后注册您想要的任何 Converters(如果需要,包括您自己的自定义实现)。Spring Integration 中 ConversionService 的使用有两个地方。对于即时转换,您可以在 <channel> 元素中添加 "datatype" 属性,并提供您希望在该通道上允许的类的完全限定名称。以下是一个示例:
<channel id="datatypeChannel" datatype="example.Foo"/>
<beans:bean id="integrationConversionService"
class="org.springframework.context.support.ConversionServiceFactoryBean">
<beans:property name="converters">
<beans:bean class="conversion.StringToFooConverter"/>
</beans:property>
</beans:bean>
在评估 SpEL 表达式时,"integrationConversionService" 发挥着重要作用。每个表达式都针对一个 EvaluationContext 进行评估,该上下文了解 "integrationConversionService"。在 Spring Integration 中,我们依赖 SpEL 来处理所有方法调用(不仅在使用 'expression' 属性时,甚至对于 'ref' 和 'method' 配置也是如此)。这意味着您可以利用从 Message 实例绑定到方法调用的值的运行时类型转换。例如,如果您调用 FooService 但在 Message 载荷中传递了 Bar 对象,那么您只需向 "integrationConversionService" 注册一个 BarToFooConverter。此示例还展示了一种更简洁的注册 Converters 的方式。通过使用通过新的 'converter' 元素提供的命名空间支持,您甚至不需要显式定义 "integrationConversionService" bean:
<!-- FooService.process(Foo) will be invoked, even though the Message payload is a Bar instance -->
<service-activator input-channel="in" ref="fooService" method="process" output-channel="out"/>
<converter>
<beans:bean class="example.BarToFooConverter"/>
</converter>
Spring Integration 1.0 有自己的 TaskScheduler 实现以及基于间隔和 cron 的 Trigger 实现。现在 Spring 3.0 提供了 TaskScheduler 和 Trigger,我们可以依赖它们。事实上,我们能够从 Spring Integration 中移除大量代码,并将其中一部分贡献回底层框架(例如,轻量级的 CronTrigger 实现)。任何轮询消费者都可以使用显式的 <poller> 子元素进行配置(否则,它将依赖于单个默认的 poller 配置)。这些 poller 元素接受以下属性之一:“fixed-delay”、“fixed-rate”或“cron”。事实上,您甚至可以提供 Spring 的 Trigger 接口的自定义实现,然后将 'trigger' 属性用作引用。以下是一个带有 cron 表达式的 poller 示例:
<file:inbound-channel-adapter directory="/some/path">
<poller cron="*/10 * 9-17 * * MON-FRI"/>
</file:inbound-channel-adapter>
我们的出站 HTTP 适配器现在委托给 Spring 的 RestTemplate 来执行 HTTP 请求和处理其响应。这意味着 HttpMessageConverter 策略起着核心作用。我们默认启用了几种转换器,但您可以完全自定义列表和/或添加自己的实现。我们实际上在 HTTP 入站适配器中也使用了相同的 HttpMessageConverter 策略。利用 RestTemplate 的另一个很好的功能是 URI 占位符的使用。以下 HTTP 出站消息网关的示例演示了自定义 HttpMessageConverter 和 URI 占位符的使用。事实上,在 URI 中替换的值是运行时对 Message 载荷进行 SpEL 评估的结果:
<http:outbound-gateway id="trafficService"
url="http://example/traffic/{zipCode}"
request-channel="requestChannel"
reply-channel="responseChannel"
http-method="GET"
message-converters="trafficConverter"
expected-response-type="example.Traffic">
<http:uri-variable name="zipCode" expression="payload.address.zipcode"/>
</http:outbound-gateway>
在 2.0 版本中,我们还增加了对 Hohpe 和 Woolf 的 企业集成模式 书籍中描述的更多模式的支持。
通过在应用程序上下文中启用消息历史记录,将向每条消息添加一个头。该头跟踪所有遍历的组件,包括每个通道和端点的名称以及遍历的时间戳。对于异步交互和可能跨越多个线程的流程很常见的消息传递应用程序,监控和审计可能是一个重大挑战。这个简单的头对于解决这个挑战非常有用,即使它只在开发时启用。切换该功能非常简单;只需在配置中添加或删除 <message-history> 元素。默认情况下,它将跟踪每个通道和端点的历史记录,但可以通过简单的名称模式进行微调:
<message-history tracked-components="*Service, foo*"/>
Message Store 提供了一种持久化消息的方法,用于任何可能在单个事务中花费过长时间处理的过程。例如,通过使用新的 MessageStore 后备 Message Channel,您可以实现缓冲:
<aggregator input-channel="in" ref="aggregator"
message-store="messageStore" output-channel="out"/>
<int-jdbc:message-store id="messageStore" data-source="dataSource"/>
Claim Check 模式背后的想法是,您可以将 Message 载荷替换为“claim ticket”,反之亦然。这允许您减少带宽和/或避免在跨通道发送消息时出现潜在的安全问题。您可以将其视为“按引用传递”,而不是典型的“按值传递”语义。我们的实现直接构建在我们上面提到的 Message Store 支持之上。“claim-check-in”和“claim-check-out”转换器对应该共享对同一 Message Store 的引用。为了方便起见,将首先考虑一个名为“messageStore”的单个 bean。如有必要,您可以通过 'message-store' 属性提供显式引用:
<claim-check-in input-channel="payloadsIn" output-channel="ticketsOut"/>
<claim-check-out input-channel="ticketsIn" output-channel="payloadsOut"/>
Control Bus 允许您使用消息来管理和监视端点和通道。事实上,这是一个相当通用的机制,您可以通过它发送一个 Message,其载荷实际上是一个 SpEL 表达式,用于在您的集成应用程序中的某个组件上进行评估。例如,您可以将 "@somePoller.stop()" 的载荷发送到 Control Bus 的输入通道。为了启用此功能,只需添加元素:
<control-bus input-channel="controlChannel"/>
我们在 Spring Integration 2.0 中添加了几个新的 Channel Adapters 和 Messaging Gateways。为了避免为其中一些重复配置示例(它们在文档中已经讲得很清楚),我将简单地提供指向 Spring Integration 参考手册相关部分的链接。
还有一些其他功能将在 GA 参考手册中介绍,但我在此提供简要说明和/或相关链接。FTP 和 SFTP 适配器在 Josh Long 的 这篇最新博文 中得到了详细介绍。
我们还增加了 RSS/Atom Feed 读取支持。以下是一个示例:
<feed:inbound-channel-adapter channel="newsChannel" url="http://example/news/rss.xml"/>
以及大家最喜欢的:Twitter 适配器。我们支持入站和出站状态更新以及直接消息。这是一个简单的示例。如您所见,它允许配置一个支持 OAuth 的 Twitter 连接实例:
<twitter:outbound-update-channel-adapter channel="tweets"
twitter-connection="twitterConnection"/>
<twitter:twitter-connection id="twitterConnection"
consumer-key="${twitter.oauth.consumerKey}"
consumer-secret="${twitter.oauth.consumerSecret}"
access-token="${twitter.oauth.accessToken}"
access-token-secret="${twitter.oauth.accessTokenSecret}"/>
与上面显示的 SpEL 示例一样,您实际上可以使用 Groovy 脚本来实现任何 transformer、filter、router、splitter 等。脚本可以非常简单,并且可以利用在运行时绑定到脚本执行上下文的 'payload' 和 'headers'。例如,以下 Groovy 脚本可以定义为 'LengthRouter.groovy':
return payload.length() > 100 ? 'long' : 'short'
然后,您可以从 router 元素(或任何其他核心元素类型)中引用它。您可以提供一个 'refresh-check-delay',以便在运行时可以拾取脚本中的更改:
<router input-channel="strings">
<int-groovy:script location="example/LengthRouter.groovy" refresh-check-delay="10000"/>
</router>
当然,您可以在 Groovy 脚本中做更多的事情。总的来说,Groovy 脚本选项在 SpEL 和 POJO 之间提供了一个很好的中间地带。
这些对称的 transformer 将载荷对象转换为/从 Map,其中 Map 中的键可以通过 SpEL 持有“平面”属性路径(例如 'customer.address.city')。
<object-to-map-transformer input-channel="objectsIn" output-channel="mapsOut"/>
<map-to-object-transformer input-channel="mapsIn" output-channel="objectsOut"/>
这些对称的 transformer 将载荷对象转换为/从 JSON。它们使用 Jackson 库,如果您需要自定义行为,可以引用 'object-mapper'。
<object-to-json-transformer input-channel="objectsIn" output-channel="jsonOut"/>
<json-to-object-transformer input-channel="jsonIn" output-channel="objectsOut"/>
这些对称的 transformer 将载荷对象转换为/从字节数组。虽然在 2.0 版本中并不全是新的,但这些 transformer 现在委托给一对新的策略接口。默认策略是标准的 Java 序列化。但是,您可以选择提供一个 'serializer'(或反序列化 transformer 的 'deserializer')属性值来引用任何 Serializer(或 Deserializer)实现。这些是 Spring 3.0.5 中提供的新策略接口。这些相同的策略也在 JDBC MessageStore 和 TCP/UDP 适配器中使用。同样,随着 Spring Data 项目的发展,您可以期待看到许多新实现。
<payload-serializing-transformer input-channel="objectsIn" output-channel="bytesOut"
serializer="someCustomSerializer"/>
<payload-deserializing-transformer input-channel="bytesIn" output-channel="objectsOut"
deserializer="someCustomDeserializer">
最后,我想指出的是,最新版本的 SpringSource Tool Suite 中包含一个令人惊叹的 Spring Integration 新可视化编辑器。如果您还没有使用 STS 2.5.0,您真的应该 立即下载!以下是我们“Cafe”示例在 STS 可视化编辑器中的截图: 
像往常一样,我的“简短”博文变成了一个史诗。好消息是,即使是看起来很长的功能列表,也只是触及了 Spring Integration 2.0 所提供功能的表面。请下载 RC1 并试用一下。一如既往,我们非常期待社区的反馈。希望您喜欢 RC1,并且通过您在 论坛 和 问题跟踪器 中的贡献,我们可以确保 2.0 GA 更好。
谢谢! -Mark