過濾器
訊息過濾器用於根據某些標準(例如訊息頭值或訊息內容本身)來決定是否應傳遞或丟棄某個 Message。因此,訊息過濾器類似於路由器,不同之處在於,對於從過濾器的輸入通道接收到的每條訊息,該訊息可能會或可能不會發送到過濾器的輸出通道。與路由器不同,它不決定將訊息傳送到哪個訊息通道,而只決定是否傳送訊息。
| 正如我們在本節後面所描述的,過濾器還支援一個丟棄通道。在某些情況下,它可以根據布林條件扮演一個非常簡單的路由器(或“開關”)的角色。 |
在 Spring Integration 中,您可以將訊息過濾器配置為委託給 MessageSelector 介面實現的訊息端點。該介面本身非常簡單,如以下列表所示:
public interface MessageSelector {
boolean accept(Message<?> message);
}
MessageFilter 建構函式接受一個選擇器例項,如以下示例所示:
MessageFilter filter = new MessageFilter(someSelector);
使用 Java、Groovy 和 Kotlin DSL 配置過濾器
Java DSL 提供的 IntegrationFlowBuilder(也用作 Groovy 和 Kotlin DSL 的基礎)為 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"/>
如果選擇器或適配的 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。框架的目標是預設情況下不完全靜默,如果需要這種行為,則需要設定一個顯式選項。
另請參閱 建議過濾器。
| 訊息過濾器通常與釋出-訂閱通道結合使用。許多過濾器端點可以訂閱同一個通道,它們決定是否將訊息傳遞給下一個端點,該端點可以是任何受支援的型別(例如服務啟用器)。這提供了一種反應式替代方法,而不是使用具有單個點對點輸入通道和多個輸出通道的訊息路由器的更主動的方法。 |
如果自定義過濾器實現在其他 <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')"/>
作為表示式屬性值傳遞的字串在評估上下文中對訊息可用的情況下作為 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 註解,則可以透過類路徑掃描自動檢測。
另請參閱 使用註解建議端點。