过滤器
消息过滤器用于根据某些条件(例如消息头值或消息内容本身)决定 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 的基础)提供的 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"/>
如果选择器或适配的 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>
在同一个 |
如果 ref
属性引用扩展 MessageFilter
的 bean(例如框架本身提供的过滤器),则通过将输出通道直接注入过滤器 bean 来优化配置。在这种情况下,每个 ref
都必须是单独的 bean 实例(或 prototype
范围的 bean)或使用内部 <bean/>
配置类型。但是,此优化仅在您未在过滤器 XML 定义中提供任何特定于过滤器的属性时才适用。如果您不小心从多个 bean 引用了相同的消息处理器,则会收到配置异常。
随着 SpEL 支持的引入,Spring Integration 向 filter 元素添加了 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' 文件(或任何具有 locale 扩展的更具体版本,以资源束加载的典型方式解析)可以包含一个键/值对,如以下示例所示:
filterPatterns.example=payload > 100
所有这些使用 |
使用注解配置过滤器
以下示例展示了如何使用注解配置过滤器:
public class PetFilter {
...
@Filter [id="CO1-1"]1
public boolean dogsOnly(String input) {
...
}
}
1 | 一个注解,指示此方法将用作过滤器。如果此类别将用作过滤器,则必须指定它。 |
XML 元素提供的所有配置选项也都适用于 @Filter
注解。
过滤器可以从 XML 显式引用,或者,如果 @MessageEndpoint
注解在类上定义,则可以通过类路径扫描自动检测。
另请参见 使用注解通知端点。