Spring Integration Java DSL 1.0 RC1 已發布

版本發布 | Artem Bilan | 2014 年 10 月 31 日 | ...

親愛的 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 方法的替代方案。 這是 FtpInboundFileSynchronizingMessageSourcelocalFilename 屬性的範例

使用 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 的其他有趣用法是 EnricherHeaderEnricher

.enrich(e -> e.requestChannel("enrichChannel")
			.requestPayload(Message::getPayload)
			.propertyFunction("date", m -> new Date()))

FunctionExpression 還支援標準 SpelExpression 中完成的執行階段類型轉換。

SubFlows

我們為某些 if...elsepublish-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 JIRAGitHub) 並在我們在大約幾週內 GA 之前盡快回報您發現的問題。

一如既往,我們非常歡迎 貢獻

取得 Spring 電子報

透過 Spring 電子報保持聯繫

訂閱

領先一步

VMware 提供培訓和認證,以加速您的進展。

了解更多

取得支援

Tanzu Spring 在一個簡單的訂閱中為 OpenJDK™、Spring 和 Apache Tomcat® 提供支援和二進位檔。

了解更多

即將舉行的活動

查看 Spring 社群中所有即將舉行的活動。

檢視全部