跳到主要内容

过滤器

QWen Plus 中英对照 Filter

消息过滤器用于根据某些标准决定是否应传递 Message ,例如消息头值或消息内容本身。因此,消息过滤器类似于路由器,不同之处在于,对于从过滤器的输入通道接收到的每个消息,该消息可能会也可能不会被发送到过滤器的输出通道。与路由器不同,它不决定将消息发送到哪个消息通道,而只决定是否发送消息。

备注

如我们在本节后面所述,过滤器还支持一个丢弃通道。在某些情况下,它可以根据布尔条件充当一个非常简单的路由器(或“交换机”)。

在 Spring Integration 中,你可以配置一个消息过滤器作为消息端点,它委托给 MessageSelector 接口的实现。该接口本身非常简单,如下所示:

public interface MessageSelector {

boolean accept(Message<?> message);

}
java

MessageFilter 构造函数接受一个选择器实例,如下例所示:

MessageFilter filter = new MessageFilter(someSelector);
java

使用 Java、Groovy 和 Kotlin DSL 配置过滤器

Java DSL 提供的 IntegrationFlowBuilder(也是 Groovy 和 Kotlin DSL 的基础)为 filter() 操作符提供了多个重载方法。上面提到的 MessageSelector 抽象可以在 filter() 定义中用作 Lambda:

@Bean
public IntegrationFlow someFlow() {
return f -> f
.<String>filter((payload) -> !"junk".equals(payload));
}
java

有关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"/>
xml

或者,你可以添加 method 属性。在这种情况下,ref 属性可以引用任何对象。引用的方法可能期望接收 Message 类型或传入消息的有效载荷类型。该方法必须返回一个布尔值。如果方法返回 'true',消息将被发送到输出通道。以下示例展示了如何配置使用 method 属性的过滤器:

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

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

如果选择器或适配的 POJO 方法返回 false,有几个设置可以控制被拒绝消息的处理。默认情况下(如果配置为前面的示例),被拒绝的消息将被静默丢弃。如果拒绝应该导致错误条件,则将 throw-exception-on-rejection 属性设置为 true,如下例所示:

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

如果你想将被拒绝的消息路由到特定的通道,请将该引用提供为 discard-channel,如下例所示:

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

如果 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>
xml
备注

在同一 <filter> 配置中使用 ref 属性和内部处理器定义是不允许的,因为它会创建一个模棱两可的条件并抛出异常。

important

如果 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')"/>
xml

传递给表达式属性的字符串值会被视为带有消息可用的评估上下文中的 SpEL 表达式进行评估。如果必须在应用程序上下文的作用范围内包含表达式的结果,可以使用 #{} 语法,如 SpEL 参考文档 中所定义的,如下例所示:

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

如果表达式本身需要动态化,你可以使用 'expression' 子元素。这提供了一层间接性,可以通过其键从 ExpressionSource 解析表达式。这是一个你可以直接实现的策略接口,或者你可以依赖 Spring Integration 中提供的版本,它从“资源 bundle”加载表达式,并可以在给定的秒数后检查修改。所有这些都在以下配置示例中进行了演示,其中如果底层文件已被修改,表达式可以在一分钟内重新加载:

<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>
xml

如果 ExpressionSource bean 被命名为 expressionSource,则无需在 <expression> 元素上提供 source 属性。但是,在前面的例子中,我们为了完整性而展示了它。

'config/integration/expressions.properties' 文件(或任何更具体的带有区域设置扩展名的版本,以通常加载资源包的方式解析)可以包含一个键值对,如下例所示:

filterPatterns.example=payload > 100
none
备注

所有这些使用 expression 作为属性或子元素的例子也可以应用于 transformer、router、splitter、service-activator 和 header-enricher 元素中。给定组件类型的语义和作用会影响对评估结果的解释,就像方法调用的返回值会被解释一样。例如,表达式可以返回字符串,这些字符串将被视为由路由器组件处理的消息通道名称。然而,在消息作为根对象评估表达式并解析以 '@' 开头的 bean 名称的功能在 Spring Integration 的所有核心 EIP 组件中是一致的。

使用注解配置过滤器

以下示例展示了如何通过使用注解来配置过滤器:

public class PetFilter {
...
@Filter 1
public boolean dogsOnly(String input) {
...
}
}
java
  • 表示此方法将用作过滤器的注解。如果此类要用作过滤器,则必须指定它。

XML 元素提供的所有配置选项也适用于 @Filter 注解。

过滤器可以显式地从 XML 中引用,或者如果类上定义了 @MessageEndpoint 注解,则可以通过类路径扫描自动检测。