Configuring a Generic Router

Spring Integration 提供了一个泛型路由器。你可以使用它进行通用路由(与 Spring Integration 提供的其他路由器相反,每个路由器都有某种形式的专业化)。

Spring Integration provides a generic router. You can use it for general-purpose routing (as opposed to the other routers provided by Spring Integration, each of which has some form of specialization).

下一部分介绍了带有 XML 组件的路由器配置。

The following section explains a router configuration with an XML components.

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

The router element provides a way to connect a router to an input channel and also accepts the optional default-output-channel attribute. The ref attribute references the bean name of a custom router implementation (which must extend AbstractMessageRouter). The following example shows three generic routers:

<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 的路由器:

Alternatively, ref may point to a POJO that contains the @Router annotation (shown later), or you can combine the ref with an explicit method name. Specifying a method applies the same behavior described in the @Router annotation section, later in this document. The following example defines a router that points to a POJO in its ref attribute:

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

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

We generally recommend using a ref attribute if the custom router implementation is referenced in other <router> definitions. However, if the custom router implementation should be scoped to a single definition of the <router>, you can provide an inner bean definition, as the following example shows:

<int:router method="someMethod" input-channel="input3"
            default-output-channel="defaultOutput3">
    <beans:bean class="org.foo.MyCustomRouter"/>
</int:router>

在同一个 <router> 配置中同时使用 ref 属性和内部处理程序是不被允许的。这样做会产生一个模糊条件并抛出一个异常。

Using both the ref attribute and an inner handler definition in the same <router> configuration is not allowed. Doing so creates an ambiguous condition and throws an exception.

如果 ref 属性引用扩展 AbstractMessageProducingHandler 的 bean(例如框架自身提供的路由器),则会优化配置以直接引用路由器。在这种情况下,每个 ref 属性都必须引用一个单独的 bean 实例(或一个 prototype 作用域 bean)或使用内部 <bean/> 配置类型。但是,此优化仅在你不提供路由器 XML 定义中的任何路由器特定属性时才适用。如果你无意中从多个 bean 引用同一个消息处理程序,则会得到一个配置异常。

If the ref attribute references a bean that extends AbstractMessageProducingHandler (such as routers provided by the framework itself), the configuration is optimized to reference the router directly. In this case, each ref attribute must refer to a separate bean instance (or a prototype-scoped bean) or use the inner <bean/> configuration type. However, this optimization applies only if you do not provide any router-specific attributes in the router XML definition. If you inadvertently reference the same message handler from multiple beans, you get a configuration exception.

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

The following example shows the equivalent router configured in 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 配置的等效路由器:

The following example shows the equivalent router configured by using the 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
        }

    };
}

或者,你可以按消息负载中的数据进行路由,如下例所示:

Alternately, you can route on data from the message payload, as the following example shows:

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