服務啟用器

服務啟用器是用於將任何 Spring 管理的物件連線到輸入通道的端點型別,以便它能夠扮演服務的角色。如果服務產生輸出,它也可以連線到輸出通道。或者,輸出生成服務可以位於處理管道或訊息流的末尾,在這種情況下,可以使用入站訊息的 replyChannel 頭部。如果未定義輸出通道,則這是預設行為。與此處描述的大多數配置選項一樣,相同的行為實際上適用於大多數其他元件。

服務啟用器本質上是一個通用端點,用於呼叫帶有輸入訊息(有效載荷和頭部)的某個物件上的方法。其內部邏輯基於 MessageHandler,它可以是特定用例的任何可能實現,例如 DefaultMessageSplitterAggregatingMessageHandlerSftpMessageHandlerJpaOutboundGateway 等。因此,本參考手冊中提到的任何出站閘道器和出站通道介面卡都應被視為此服務啟用器端點的特定擴充套件;它們最終都呼叫某個物件的方法。

配置服務啟用器

使用 Java 和註解配置時,只需用 @ServiceActivator 註解標記相應的服務方法即可——框架會在訊息從輸入通道消費時呼叫它。

public class SomeService {

    @ServiceActivator(inputChannel = "exampleChannel")
    public void exampleHandler(SomeData payload) {
        ...
    }

}

有關更多資訊,請參閱 註解支援

對於 Java、Groovy 或 Kotlin DSL,IntegrationFlow.handle() 運算子表示一個服務啟用器。

  • Java DSL

  • Kotlin DSL

  • Groovy DSL

@Bean
public IntegrationFlow someFlow() {
    return IntegrationFlow
             .from("exampleChannel")
             .handle(someService, "exampleHandler")
             .get();
}
@Bean
fun someFlow() =
    integrationFlow("exampleChannel") {
        handle(someService, "exampleHandler")
    }
@Bean
someFlow() {
    integrationFlow 'exampleChannel',
            {
                handle someService, 'exampleHandler'
            }
}

有關 DSL 的更多資訊,請參閱相關章節

在使用 XML 配置時建立服務啟用器,請使用帶有 'input-channel' 和 'ref' 屬性的 'service-activator' 元素,如下例所示:

<int:service-activator input-channel="exampleChannel" ref="exampleHandler"/>

前面的配置從 exampleHandler 中選擇所有符合以下訊息要求的方法:

  • @ServiceActivator 註解。

  • public 的。

  • 如果 requiresReply == true,則不返回 void

執行時呼叫的目標方法是根據每個請求訊息的 payload 型別選擇的,或者如果目標類上存在 Message<?> 型別的方法,則回退到該方法。

從版本 5.0 開始,可以使用 @org.springframework.integration.annotation.Default 標記一個服務方法,作為所有不匹配情況的備用。這在使用 內容型別轉換 且目標方法在轉換後被呼叫時非常有用。

要委託給任何物件的顯式定義方法,可以新增 method 屬性,如下例所示:

<int:service-activator input-channel="exampleChannel" ref="somePojo" method="someMethod"/>

無論哪種情況,當服務方法返回一個非空值時,端點都會嘗試將回復訊息傳送到適當的回覆通道。為了確定回覆通道,它首先檢查端點配置中是否提供了 output-channel,如下例所示:

<int:service-activator input-channel="exampleChannel" output-channel="replyChannel"
                       ref="somePojo" method="someMethod"/>

如果方法返回結果且未定義 output-channel,則框架會檢查請求訊息的 replyChannel 頭部值。如果該值可用,它會檢查其型別。如果它是 MessageChannel,則回覆訊息將傳送到該通道。如果它是 String,則端點會嘗試將通道名稱解析為通道例項。如果無法解析通道,則會丟擲 DestinationResolutionException。如果可以解析,訊息將傳送到那裡。如果請求訊息沒有 replyChannel 頭部且 reply 物件是 Message,則會查詢其 replyChannel 頭部以獲取目標目的地。這是 Spring Integration 中請求-回覆訊息傳遞使用的技術,它也是返回地址模式的一個示例。

如果您的方法返回一個結果,並且您希望丟棄它並結束流,您應該將 output-channel 配置為傳送到 NullChannel。為了方便起見,框架註冊了一個名為 nullChannel 的通道。有關更多資訊,請參閱 特殊通道

服務啟用器是那些不需要生成回覆訊息的元件之一。如果您的方法返回 null 或具有 void 返回型別,則服務啟用器在方法呼叫後退出,沒有任何訊號。此行為可以透過 AbstractReplyProducingMessageHandler.requiresReply 選項控制,該選項在使用 XML 名稱空間配置時也作為 requires-reply 公開。如果此標誌設定為 true 且方法返回 null,則會丟擲 ReplyRequiredException

服務方法中的引數可以是訊息,也可以是任意型別。如果是後者,則假定它是訊息有效載荷,它從訊息中提取並注入到服務方法中。我們通常推薦這種方法,因為它在與 Spring Integration 合作時遵循並促進 POJO 模型。引數還可以帶有 @Header@Headers 註解,如 註解支援 中所述。

服務方法不需要任何引數,這意味著您可以實現事件式服務啟用器(您只關心服務方法的呼叫),而不必擔心訊息的內容。將其視為一個 null JMS 訊息。此類實現的示例用例是對輸入通道上存款訊息的簡單計數器或監視器。

從版本 4.1 開始,框架正確地將訊息屬性(payloadheaders)轉換為 Java 8 Optional POJO 方法引數,如下例所示:

public class MyBean {
    public String computeValue(Optional<String> payload,
               @Header(value="foo", required=false) String foo1,
               @Header(value="foo") Optional<String> foo2) {
        if (payload.isPresent()) {
            String value = payload.get();
            ...
        }
        else {
           ...
       }
    }

}

如果自定義服務啟用器處理程式實現可以在其他 <service-activator> 定義中重用,我們通常建議使用 ref 屬性。但是,如果自定義服務啟用器處理程式實現僅在 <service-activator> 的單個定義中使用,則可以提供內部 bean 定義,如下例所示:

<int:service-activator id="exampleServiceActivator" input-channel="inChannel"
            output-channel = "outChannel" method="someMethod">
    <beans:bean class="org.something.ExampleServiceActivator"/>
</int:service-activator>
在同一個 <service-activator> 配置中同時使用 ref 屬性和內部處理程式定義是不允許的,因為它會建立歧義條件並導致丟擲異常。
如果 ref 屬性引用了擴充套件 AbstractMessageProducingHandler 的 bean(例如框架本身提供的處理程式),則透過將輸出通道直接注入處理程式來最佳化配置。在這種情況下,每個 ref 都必須是單獨的 bean 例項(或 prototype 作用域的 bean),或者使用內部 <bean/> 配置型別。如果您不小心從多個 bean 引用了相同的訊息處理程式,則會收到配置異常。

服務啟用器和 Spring 表示式語言 (SpEL)

自 Spring Integration 2.0 起,服務啟用器也可以受益於 SpEL

例如,您可以在不指向 ref 屬性中的 bean 或將其作為內部 bean 定義的情況下呼叫任何 bean 方法,如下所示:

<int:service-activator input-channel="in" output-channel="out"
	expression="@accountService.processAccount(payload, headers.accountId)"/>

	<bean id="accountService" class="thing1.thing2.Account"/>

在前面的配置中,我們沒有使用 ref 或作為內部 bean 注入“accountService”,而是使用 SpEL 的 @beanId 符號並呼叫一個接受與訊息有效負載相容的型別的方法。我們還傳遞了一個頭部值。任何有效的 SpEL 表示式都可以根據訊息中的任何內容進行評估。對於簡單場景,如果所有邏輯都可以封裝在這樣的表示式中,您的服務啟用器就不需要引用 bean,如下例所示:

<int:service-activator input-channel="in" output-channel="out" expression="payload * 2"/>

在前面的配置中,我們的服務邏輯是將有效載荷值乘以二。SpEL 讓我們相對容易地處理它。

有關配置服務啟用器的更多資訊,請參閱 Java DSL 章中的 服務啟用器和 .handle() 方法

非同步服務啟用器

服務啟用器由呼叫執行緒呼叫。如果輸入通道是 SubscribableChannel,則這是上游執行緒;如果是 PollableChannel,則這是輪詢器執行緒。如果服務返回 CompletableFuture<?>,則預設操作是將其作為傳送到輸出(或回覆)通道的訊息的有效載荷傳送。從版本 4.3 開始,您現在可以將 async 屬性設定為 true(在使用 Java 配置時使用 setAsync(true))。如果服務返回 CompletableFuture<?> 且此 async 屬性設定為 true,則呼叫執行緒會立即釋放,並且回覆訊息會在完成 Future 的執行緒(來自您的服務內部)上傳送。這對於使用 PollableChannel 的長時間執行的服務特別有利,因為輪詢器執行緒被釋放以在框架內執行其他服務。

如果服務以 Exception 完成 future,則會發生正常的錯誤處理。如果存在 errorChannel 訊息頭部,則會發送 ErrorMessage。否則,會將 ErrorMessage 傳送到預設的 errorChannel(如果可用)。

從版本 6.1 開始,如果 AbstractMessageProducingHandler 的輸出通道配置為 ReactiveStreamsSubscribableChannel,則預設開啟非同步模式。如果處理程式結果不是響應式型別或 CompletableFuture<?>,則儘管輸出通道型別,也會發生常規的回覆生成過程。

另請參閱 Reactive Streams 支援 以獲取更多資訊。

服務啟用器和方法返回型別

服務方法可以返回任何型別,該型別將成為回覆訊息有效載荷。在這種情況下,將建立一個新的 Message<?> 物件,並複製請求訊息中的所有頭部。這對於大多數 Spring Integration MessageHandler 實現以相同的方式工作,當互動基於 POJO 方法呼叫時。

方法也可以返回一個完整的 Message<?> 物件。但是,請記住,與 轉換器 不同,對於服務啟用器,如果返回訊息中不存在請求訊息的頭部,則會透過複製請求訊息的頭部來修改此訊息。因此,如果您的方法引數是 Message<?> 並且您在服務方法中複製了一些(但不是全部)現有頭部,它們將再次出現在回覆訊息中。服務啟用器沒有責任從回覆訊息中刪除頭部,並且為了遵循松耦合原則,最好在整合流中新增 HeaderFilter。或者,可以使用 Transformer 而不是服務啟用器,但在這種情況下,當返回完整的 Message<?> 時,方法完全負責該訊息,包括複製請求訊息頭部(如果需要)。您必須確保保留重要的框架頭部(例如 replyChannelerrorChannel)(如果存在)。

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