DSL 基礎

org.springframework.integration.dsl 套件包含先前提及的 IntegrationFlowBuilder API 和許多 IntegrationComponentSpec 實作,這些實作也是建構器,並提供流暢的 API 來設定具體端點。 IntegrationFlowBuilder 基礎架構為基於訊息的應用程式提供常見的企業整合模式 (EIP),例如通道、端點、pollers 和通道攔截器。

重要

IntegrationComponentSpecFactoryBean 實作,因此不得從 bean 定義中呼叫其 getObject() 方法。 IntegrationComponentSpec 實作必須保持原樣用於 bean 定義,並且框架將管理其生命週期。 目標 IntegrationComponentSpec 類型 (FactoryBean 值) 的 Bean 方法參數注入必須用於 IntegrationFlow bean 定義,而不是 bean 方法參考。

端點在 DSL 中以動詞表示,以提高可讀性。 以下列表包含常見的 DSL 方法名稱和相關聯的 EIP 端點

  • 轉換 → Transformer

  • 篩選 → Filter

  • 處理 → ServiceActivator

  • 分割 → Splitter

  • 彙總 → Aggregator

  • 路由 → Router

  • 橋接 → Bridge

從概念上講,整合程序是透過將這些端點組合成一個或多個訊息流來建構的。 請注意,EIP 並未正式定義術語「訊息流」,但將其視為使用眾所周知的訊息傳遞模式的工作單元很有用。 DSL 提供 IntegrationFlow 元件來定義通道和它們之間的端點的組合,但現在 IntegrationFlow 僅扮演配置角色,以在應用程式上下文中填充真實的 bean,並且在執行時期不使用。 但是,IntegrationFlow 的 bean 可以作為 Lifecycle 自動裝配,以控制整個流程的 start()stop(),這會委派給與此 IntegrationFlow 相關聯的所有 Spring Integration 元件。 以下範例使用 IntegrationFlow 流暢的 API,透過使用 IntegrationFlowBuilder 的 EIP 方法來定義 IntegrationFlow bean

@Bean
public IntegrationFlow integerFlow() {
    return IntegrationFlow.from("input")
            .<String, Integer>transform(Integer::parseInt)
            .get();
}

transform 方法接受 lambda 作為端點引數,以對訊息酬載進行操作。 此方法的真正引數是 GenericTransformer<S, T> 實例。 因此,任何提供的轉換器 (ObjectToJsonTransformerFileToStringTransformer 和其他) 都可以在此處使用。

在底層,IntegrationFlowBuilder 辨識 MessageHandler 及其端點,分別為 MessageTransformingHandlerConsumerEndpointFactoryBean。 請考慮另一個範例

@Bean
public IntegrationFlow myFlow() {
    return IntegrationFlow.from("input")
                .filter("World"::equals)
                .transform("Hello "::concat)
                .handle(System.out::println)
                .get();
}

前面的範例組成 Filter → Transformer → Service Activator 的序列。 流程是「單向」的。 也就是說,它不提供回覆訊息,而僅將酬載列印到 STDOUT。 端點會透過使用直接通道自動連接在一起。

Lambdas 和 Message<?> 引數

當在 EIP 方法中使用 lambdas 時,「輸入」引數通常是訊息酬載。 如果您希望存取整個訊息,請使用其中一個採用 Class<?> 作為第一個參數的重載方法。 例如,這將不起作用

.<Message<?>, Foo>transform(m -> newFooFromMessage(m))

這將在執行時期因 ClassCastException 而失敗,因為 lambda 不會保留引數類型,並且框架將嘗試將酬載轉換為 Message<?>

相反地,使用

.(Message.class, m -> newFooFromMessage(m))
Bean 定義覆寫

Java DSL 可以為流程定義中內嵌定義的物件註冊 bean,也可以重複使用現有的注入 bean。 如果為內嵌物件和現有的 bean 定義定義了相同的 bean 名稱,則會擲回 BeanDefinitionOverrideException,表示此類配置是錯誤的。 但是,當您處理 prototype bean 時,無法從整合流程處理器偵測現有的 bean 定義,因為每次我們從 BeanFactory 呼叫 prototype bean 時,我們都會獲得一個新實例。 這樣,提供的實例會按原樣在 IntegrationFlow 中使用,而無需任何 bean 註冊以及任何針對現有 prototype bean 定義的可能檢查。 但是,如果此物件具有明確的 id 且此名稱的 bean 定義在 prototype 範圍內,則會為此物件呼叫 BeanFactory.initializeBean()