DSL 基礎

org.springframework.integration.dsl 包包含前面提到的 IntegrationFlowBuilder API 以及許多 IntegrationComponentSpec 實現。這些實現也是構建器,提供流式 API 來配置具體的端點。IntegrationFlowBuilder 基礎設施為基於訊息的應用程式提供常見的企業整合模式(EIP),例如通道、端點、輪詢器和通道攔截器。

重要

IntegrationComponentSpec 是一個 FactoryBean 實現,因此不能從 bean 定義中呼叫其 getObject() 方法。IntegrationComponentSpec 實現必須保持原樣用於 bean 定義,並且框架將管理其生命週期。對於 IntegrationFlow bean 定義,必須使用目標 IntegrationComponentSpec 型別(FactoryBean 值)的 bean 方法引數注入,而不是 bean 方法引用。

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

  • transform → Transformer

  • filter → Filter

  • handle → ServiceActivator

  • split → Splitter

  • aggregate → Aggregator

  • route → Router

  • bridge → 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。端點透過使用直接通道自動連線。

Lambda 表示式和 Message<?> 引數

在 EIP 方法中使用 lambda 表示式時,“輸入”引數通常是訊息負載。如果您希望訪問整個訊息,請使用採用 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()

© . This site is unofficial and not affiliated with VMware.