篩選器

訊息篩選器用於根據某些標準(例如訊息標頭值或訊息內容本身)來決定是否應傳遞或捨棄 Message。因此,訊息篩選器類似於路由器,不同之處在於,對於從篩選器的輸入通道接收到的每則訊息,同一則訊息可能會或可能不會被傳送到篩選器的輸出通道。與路由器不同,它不會決定將訊息傳送到哪個訊息通道,而僅決定是否完全傳送訊息。

如本節稍後所述,篩選器也支援捨棄通道。在某些情況下,它可以根據布林條件,扮演非常簡單的路由器(或「交換器」)的角色。

在 Spring Integration 中,您可以將訊息篩選器設定為訊息端點,該端點委派給 MessageSelector 介面的實作。該介面本身非常簡單,如下列清單所示

public interface MessageSelector {

    boolean accept(Message<?> message);

}

MessageFilter 建構子接受 selector 實例,如下列範例所示

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"/>

如果 selector 或調整後的 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 屬性和內部處理器定義,因為它會產生不明確的條件並擲回例外狀況。
如果 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 作為屬性或子元素的範例也可以應用於轉換器、路由器、分割器、服務啟動器和標頭豐富器元素中。給定元件類型的語意和角色會影響評估結果的解讀,就像方法調用的傳回值會被解讀一樣。例如,表達式可以傳回字串,這些字串將被路由器元件視為訊息通道名稱。但是,針對訊息作為根物件評估表達式以及在以 '@' 為前綴時解析 bean 名稱的底層功能在 Spring Integration 內的所有核心 EIP 元件中都是一致的。

使用註解設定篩選器

下列範例示範如何使用註解設定篩選器

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

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

篩選器可以從 XML 明確參考,或者,如果在類別上定義了 @MessageEndpoint 註解,則可以透過類別路徑掃描自動偵測。