領先一步
VMware 提供培訓和認證,以加速您的進展。
了解更多親愛的 Spring 社群:
我們很高興宣布,在 Spring Integration 4.1 Release Candidate 之後不久,Spring Integration Java DSL 1.0 Release Candidate 現在也已可用。請使用 Maven 或 Gradle 透過 里程碑存放庫,或下載 發布檔案,以試用看看。
請參閱專案的 首頁 以取得更多資訊。
此版本包含許多新功能和改進,以及一些錯誤修正。GA 正式版計畫於 11 月中旬發布。
以下是自從 上次里程碑 以來的主要變更摘要
重構和重大變更
Spring Integration Java DSL 主要針對 Java 8 及其 Lambda 支援,但仍然支援較早的 Java 版本。 我們已經移除了幾個 functional interfaces
,而改用 Java 8 中類似的介面:Consumer<T>
、Function<T, R>
等。當然,為了支援與舊 Java 版本的向後相容性,我們在 DSL 原始碼中實作了類似的介面。 使用變更後介面的 Java 8 之前的版本的用戶需要進行變更以修復其編譯錯誤。 例如
從這個
.handle(Integer.class, (p, h) -> p * 2,
new EndpointConfigurer<GenericEndpointSpec<ServiceActivatingHandler>>() {
@Override
public void accept(GenericEndpointSpec<ServiceActivatingHandler> spec) {
spec.poller(Pollers.cron("7 * * * * ?"));
}
})
到這個
.handle(Integer.class, (p, h) -> p * 2,
new Consumer<GenericEndpointSpec<ServiceActivatingHandler>>() {
@Override
public void accept(GenericEndpointSpec<ServiceActivatingHandler> spec) {
spec.poller(Pollers.cron("7 * * * * ?"));
}
})
當然,如果您在這裡使用 Java 8 Lambda,則程式碼將不需要變更
.handle(Integer.class, (p, h) -> p * 2, e -> e.poller(Pollers.cron("7 * * * * ?")))
IntegrationFlows
現在僅包含 from(...)
方法。 .fromFixedMessageChannel()
已被 .from(String messageChannelName, boolean fixedSubscriber)
取代。
此外,為了修復一些封裝混亂問題,我們已將某些類別移動到不同的封裝。
方法範圍函式
為了簡化 IDE 中的程式碼完成並避免冗餘搜尋所需的 Namespace Factory
,我們新增了具有 Function<T, R>
引數的重載方法。 例如,以下程式碼片段相等
.....
.channel(Amqp.pollableChannel(this.rabbitConnectionFactory)
.queueName("amqpReplyChannel")
.channelTransacted(true))
....
.channel(c -> c.amqpPollable(this.rabbitConnectionFactory)
.queueName("amqpReplyChannel")
.channelTransacted(true))
....
其中 c
變數是 Channel
的 "method-aggregator" 物件,它委派給適當的 Namespace Factory
。 其他類似的 Lambda 方法為
IntegrationFlows.from(MessageSourcesFunction sources)
IntegrationFlows.from(MessageProducersFunction producers)
IntegrationFlows.from(MessagingGatewaysFunction gateways)
IntegrationFlowDefinition.handleWithAdapter(Function<Adapters, MessageHandlerSpec<?, H>> adapters)
EndpointSpec.poller(Function<PollerFactory, PollerSpec> pollers)
FunctionExpression
Spring Integration 具有驚人的 Spring Expression Language (SpEL) 支援。 由於 Java DSL 是純 (eh!) Java,因此在 expression
屬性的長字串中指定一些業務邏輯沒有意義。 受到 Java 8 Lambda 支援的啟發,並追求最小變更的目標,我們引入了 FunctionExpression
- SpEL Expression
介面的實作 - 它接受 Function<T, R>
並在每個 getValue()
上委派給它。 現在,DSL 中的許多元件都提供 (Function<T, R> function)
方法作為類似 SpEL 方法的替代方案。 這是 FtpInboundFileSynchronizingMessageSource
的 localFilename
屬性的範例
使用 SpEL
@Bean
public IntegrationFlow ftpInboundFlow() {
return IntegrationFlows
.from(s -> s.ftp(this.ftpSessionFactory)
.remoteDirectory("ftpSource")
.localFilenameExpression("payload.toUpperCase() + '.a'")
.channel(c -> c.queue("ftpInboundResultChannel"))
.get();
}
使用 Lambda
@Bean
public IntegrationFlow ftpInboundFlow() {
return IntegrationFlows
.from(s -> s.ftp(this.ftpSessionFactory)
.remoteDirectory("ftpSource")
.localFilename(f -> f.toUpperCase() + ".a")))
.channel(c -> c.queue("ftpInboundResultChannel"))
.get();
}
FunctionExpression
的其他有趣用法是 Enricher
和 HeaderEnricher
.enrich(e -> e.requestChannel("enrichChannel")
.requestPayload(Message::getPayload)
.propertyFunction("date", m -> new Date()))
FunctionExpression
還支援標準 SpelExpression
中完成的執行階段類型轉換。
SubFlows
我們為某些 if...else
和 publish-subscribe
元件引入了 SubFlow
支援。 最簡單的例子是 .publishSubscribeChannel()
@Bean
public IntegrationFlow subscribersFlow() {
return flow -> flow
.publishSubscribeChannel(Executors.newCachedThreadPool(), s -> s
.subscribe(f -> f
.<Integer>handle((p, h) -> p / 2)
.channel(c -> c.queue("subscriber1Results")))
.subscribe(f -> f
.<Integer>handle((p, h) -> p * 2)
.channel(c -> c.queue("subscriber2Results"))))
.<Integer>handle((p, h) -> p * 3)
.channel(c -> c.queue("subscriber3Results"));
}
當然,我們可以透過單獨的 IntegrationFlow
@Bean
定義來實現相同的結果,但我們希望您會發現邏輯組成的子流程樣式很有用。
.routeToRecipients()
提供了類似的 publish-subscribe
子流程組成。
另一個例子是 .filter()
上的 .discardFlow()
而不是 .discardChannel()
。
.route()
值得特別關注
@Bean
public IntegrationFlow routeFlow() {
return f -> f
.<Integer, Boolean>route(p -> p % 2 == 0,
m -> m.channelMapping("true", "evenChannel")
.subFlowMapping("false", sf ->
sf.<Integer>handle((p, h) -> p * 3)))
.transform(Object::toString)
.channel(c -> c.queue("oddChannel"));
}
.channelMapping()
繼續像在常規 Router
映射中一樣工作,但 .subFlowMapping()
將該子流程與主流程聯繫在一起。 換句話說,任何路由器的子流程在 .route()
之後都會返回到主流程。
.gateway()
支援類似的 "返回主流程" 子流程
@Bean
public IntegrationFlow gatewayFlow() {
return f ->
f.gateway("gatewayRequest", g -> g.errorChannel("gatewayError").replyTimeout(10L))
.gateway(gf -> gf.transform("From Gateway SubFlow: "::concat));
}
但是,此閘道子流程僅透過明確的 DirectChannel
與主流程連接,並使用該通道作為 requestChannel
選項包裝到常規 GatewayMessageHandler
中。
當然,子流程可以巢狀任何深度,但我們不建議這樣做,因為事實上,即使在路由器案例中,在流程中新增複雜的子流程也很快就會變得難以讓人解析。
結論
自上次里程碑以來,我們沒有新增更多 protocol specific adapters
。 並非所有介面卡都會直接受到 DSL 的支援,儘管最常用的介面卡具有一流的支援。 但是,那些沒有一流支援的介面卡可以使用 .handle()
輕鬆連接。 正如我們之前討論的那樣,我們正在尋找輸入來確定剩餘介面卡實作的優先順序,因此,請不要害羞分享您的想法和意見!
您可以從他們的 原始碼 和 參考手冊 中獲得有關這些和現有類別的更多資訊。
我們期待您的意見和回饋 (StackOverflow (spring-integration
標籤)、Spring JIRA、GitHub) 並在我們在大約幾週內 GA 之前盡快回報您發現的問題。
一如既往,我們非常歡迎 貢獻。