過濾器

訊息過濾器用於根據某些條件(例如訊息頭部值或訊息內容本身)來決定是否應傳遞或丟棄某個 Message。因此,訊息過濾器類似於路由器,不同之處在於,對於從過濾器輸入通道接收到的每條訊息,該同一訊息可能傳送或不傳送到過濾器的輸出通道。與路由器不同,它不決定將訊息傳送到哪個訊息通道,而只決定是否傳送訊息。

正如本節後面所述,過濾器還支援丟棄通道。在某些情況下,它可以根據布林條件充當非常簡單的路由器(或“開關”)的角色。

在 Spring Integration 中,您可以將訊息過濾器配置為訊息端點,該端點委託給 MessageSelector 介面的實現。該介面本身非常簡單,如下所示

public interface MessageSelector {

    boolean accept(Message<?> message);

}

MessageFilter 建構函式接受一個選擇器例項,如下例所示

MessageFilter filter = new MessageFilter(someSelector);

使用 Java、Groovy 和 Kotlin DSL 配置過濾器

Java DSL(也用作 Groovy 和 Kotlin DSL 的基礎)提供的 IntegrationFlowBuilderfilter() 運算子提供了多個過載方法。上面提到的 MessageSelector 抽象可以在 filter() 定義中用作 Lambda

  • Java DSL

  • Kotlin DSL

  • Groovy DSL

@Bean
public IntegrationFlow someFlow() {
    return f -> f
              .<String>filter((payload) -> !"junk".equals(payload));
}
@Bean
fun someFlow() =
    integrationFlow {
        filter<String> { it != "junk" }
    }
@Bean
someFlow() {
    integrationFlow {
        filter String, { it != 'junk' }
    }
}

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

使用 XML 配置過濾器

結合名稱空間和 SpEL,您可以使用非常少的 Java 程式碼配置強大的過濾器。

您可以使用 <filter> 元素建立訊息選擇端點。除了 input-channeloutput-channel 屬性外,它還需要一個 ref 屬性。ref 可以指向 MessageSelector 實現,如下例所示

<int:filter input-channel="input" ref="selector" output-channel="output"/>

<bean id="selector" class="example.MessageSelectorImpl"/>

或者,您可以新增 method 屬性。在這種情況下,ref 屬性可以引用任何物件。引用的方法可以期望 Message 型別或入站訊息的負載型別。該方法必須返回布林值。如果方法返回 'true',則訊息將被髮送到輸出通道。以下示例展示瞭如何配置使用 method 屬性的過濾器

<int:filter input-channel="input" output-channel="output"
    ref="exampleObject" method="someBooleanReturningMethod"/>

<bean id="exampleObject" class="example.SomeObject"/>

如果選擇器或適配的 POJO 方法返回 false,則一些設定控制拒絕訊息的處理。預設情況下(如果按前例配置),拒絕的訊息會被靜默丟棄。如果拒絕應導致錯誤情況,則將 throw-exception-on-rejection 屬性設定為 true,如下例所示

<int:filter input-channel="input" ref="selector"
    output-channel="output" throw-exception-on-rejection="true"/>

如果您希望將拒絕的訊息路由到特定通道,請將該引用作為 discard-channel 提供,如下例所示

<int:filter input-channel="input" ref="selector"
    output-channel="output" discard-channel="rejectedMessages"/>

如果 throwExceptionOnRejection == false 並且未提供 discardChannel,則訊息將被靜默丟棄,並且 o.s.i.filter.MessageFilter 例項只會發出關於此丟棄訊息的警告日誌訊息(從 6.1 版本開始)。要在日誌中不顯示警告地丟棄訊息,可以將 NullChannel 配置為過濾器的 discardChannel。該框架的目標是預設情況下不會完全靜默,如果這是所需行為,則需要設定一個顯式選項。

另請參閱 為過濾器提供 Advice

訊息過濾器通常與釋出-訂閱通道結合使用。許多過濾器端點可以訂閱到同一個通道,它們決定是否將訊息傳遞給下一個端點,下一個端點可以是任何支援的型別(例如服務啟用器)。這提供了一種響應式替代方案,與使用具有單個點對點輸入通道和多個輸出通道的訊息路由器的更主動方法不同。

如果自定義過濾器實現在其他 <filter> 定義中被引用,我們建議使用 ref 屬性。但是,如果自定義過濾器實現的作用域僅限於單個 <filter> 元素,則應提供一個內部 bean 定義,如下例所示

<int:filter method="someMethod" input-channel="inChannel" output-channel="outChannel">
  <beans:bean class="org.foo.MyCustomFilter"/>
</filter>
在同一個 <filter> 配置中同時使用 ref 屬性和內部 handler 定義是不允許的,因為它會建立模糊條件並丟擲異常。
如果 ref 屬性引用了一個擴充套件 MessageFilter 的 bean(例如框架自身提供的過濾器),則透過將輸出通道直接注入到過濾器 bean 中來最佳化配置。在這種情況下,每個 ref 都必須引用一個單獨的 bean 例項(或 prototype 作用域的 bean),或者使用內部 <bean/> 配置型別。但是,此最佳化僅在您未在過濾器 XML 定義中提供任何過濾器特定屬性時適用。如果您不小心從多個 bean 中引用了相同的訊息處理器,則會收到配置異常。

隨著 SpEL 支援的引入,Spring Integration 為過濾器元素添加了 expression 屬性。它可以用於完全避免 Java 來配置簡單的過濾器,如下例所示

<int:filter input-channel="input" expression="payload.equals('nonsense')"/>

作為 expression 屬性值傳入的字串會被評估為 SpEL 表示式,訊息可在評估上下文中獲得。如果您必須將表示式的結果包含在應用程式上下文的作用域內,您可以使用 #{} 符號,如 SpEL 參考文件 中所定義,如下例所示

<int:filter input-channel="input"
            expression="payload.matches(#{filterPatterns.nonsensePattern})"/>

如果表示式本身需要是動態的,可以使用 'expression' 子元素。這提供了一種間接層級,透過其鍵從 ExpressionSource 中解析表示式。這是一個策略介面,您可以直接實現,或者可以依賴 Spring Integration 中提供的版本,該版本從“資源包”載入表示式,並可以在給定秒數後檢查修改。所有這些都在以下配置示例中演示,如果底層檔案已被修改,表示式可以在一分鐘內重新載入

<int:filter input-channel="input" output-channel="output">
    <int:expression key="filterPatterns.example" source="myExpressions"/>
</int:filter>

<beans:bean id="myExpressions"
    class="o.s.i.expression.ReloadableResourceBundleExpressionSource">
    <beans:property name="basename" value="config/integration/expressions"/>
    <beans:property name="cacheSeconds" value="60"/>
</beans:bean>

如果 ExpressionSource bean 的名稱是 expressionSource,則無需在 <expression> 元素上提供 `source` 屬性。然而,在前面的示例中,為了完整性,我們展示了它。

'config/integration/expressions.properties' 檔案(或任何帶有語言環境副檔名的更具體版本,以載入資源包的典型方式解析)可以包含一個鍵/值對,如下例所示

filterPatterns.example=payload > 100
所有這些使用 expression 作為屬性或子元素的示例也可以應用於 transformer、router、splitter、service-activator 和 header-enricher 元素。給定元件型別的語義和角色將影響評估結果的解釋,就像方法呼叫的返回值會被解釋一樣。例如,表示式可以返回字串,這些字串將被路由器元件視為訊息通道名稱。然而,將表示式針對訊息作為根物件進行評估並在以 '@' 為字首時解析 bean 名稱的底層功能在 Spring Integration 中的所有核心 EIP 元件中是一致的。

使用註解配置過濾器

以下示例展示瞭如何使用註解配置過濾器

public class PetFilter {
    ...
    @Filter  (1)
    public boolean dogsOnly(String input) {
        ...
    }
}
1 一個註解,指示此方法將用作過濾器。如果此類別將用作過濾器,則必須指定此註解。

XML 元素提供的所有配置選項也適用於 @Filter 註解。

過濾器可以從 XML 中顯式引用,或者,如果在類上定義了 @MessageEndpoint 註解,則可以透過類路徑掃描自動檢測到。