篩選器
訊息篩選器用於根據某些標準(例如訊息標頭值或訊息內容本身)來決定是否應傳遞或捨棄 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 的基礎)提供的 IntegrationFlowBuilder
為 filter()
運算子提供了許多多載方法。上面提到的 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-channel
和 output-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
註解,則可以透過類別路徑掃描自動偵測。
另請參閱 使用註解為端點提供 Advice。