配置通用路由器

Spring Integration 提供了一个通用的路由器。您可以将其用于通用路由(与 Spring Integration 提供的其他路由器相反,每个路由器都具有一定的专业化)。

以下部分解释了使用 XML 组件的路由器配置。

router 元素提供了一种将路由器连接到输入通道的方法,并且还接受可选的 default-output-channel 属性。ref 属性引用自定义路由器实现的 bean 名称(必须扩展 AbstractMessageRouter)。以下示例显示了三个通用路由器

<int:router ref="payloadTypeRouter" input-channel="input1"
            default-output-channel="defaultOutput1"/>

<int:router ref="recipientListRouter" input-channel="input2"
            default-output-channel="defaultOutput2"/>

<int:router ref="customRouter" input-channel="input3"
            default-output-channel="defaultOutput3"/>

<beans:bean id="customRouterBean" class="org.foo.MyCustomRouter"/>

或者,ref 可以指向包含 @Router 注释的 POJO(稍后显示),或者您可以将 ref 与显式方法名称结合使用。指定方法将应用与 @Router 注释部分中描述的相同行为,该部分在本文档的后面部分。以下示例定义了一个路由器,该路由器在其 ref 属性中指向一个 POJO

<int:router input-channel="input" ref="somePojo" method="someMethod"/>

我们通常建议在自定义路由器实现被其他 <router> 定义引用时使用 ref 属性。但是,如果自定义路由器实现应该被限制在 <router> 的单个定义中,您可以提供一个内部 bean 定义,如下面的示例所示

<int:router method="someMethod" input-channel="input3"
            default-output-channel="defaultOutput3">
    <beans:bean class="org.foo.MyCustomRouter"/>
</int:router>
在同一个 <router> 配置中同时使用 ref 属性和内部处理程序定义是不允许的。这样做会创建一个模棱两可的条件并抛出异常。
如果 ref 属性引用一个扩展 AbstractMessageProducingHandler 的 bean(例如框架本身提供的路由器),则配置将被优化为直接引用路由器。在这种情况下,每个 ref 属性必须引用一个单独的 bean 实例(或一个 prototype 范围的 bean)或使用内部 <bean/> 配置类型。但是,这种优化仅在您没有在路由器 XML 定义中提供任何路由器特定属性的情况下才适用。如果您无意中从多个 bean 引用了同一个消息处理程序,您将收到一个配置异常。

以下示例展示了在 Java 中配置的等效路由器

@Bean
@Router(inputChannel = "routingChannel")
public AbstractMessageRouter myCustomRouter() {
    return new AbstractMessageRouter() {

        @Override
        protected Collection<MessageChannel> determineTargetChannels(Message<?> message) {
            return // determine channel(s) for message
        }

    };
}

以下示例展示了使用 Java DSL 配置的等效路由器

@Bean
public IntegrationFlow routerFlow() {
    return IntegrationFlow.from("routingChannel")
            .route(myCustomRouter())
            .get();
}

public AbstractMessageRouter myCustomRouter() {
    return new AbstractMessageRouter() {

        @Override
        protected Collection<MessageChannel> determineTargetChannels(Message<?> message) {
            return // determine channel(s) for message
        }

    };
}

或者,您可以根据消息有效负载中的数据进行路由,如下例所示

@Bean
public IntegrationFlow routerFlow() {
    return IntegrationFlow.from("routingChannel")
            .route(String.class, p -> p.contains("foo") ? "fooChannel" : "barChannel")
            .get();
}