[[router]]
=== Routers

This section covers how routers work.
It includes the following topics:

* <<router-overview>>
* <<router-common-parameters>>
* <<router-implementations>>
* <<router-namespace>>
* <<router-spel>>
* <<dynamic-routers>>

[[router-overview]]
==== Overview

Routers are a crucial element in many messaging architectures.
They consume messages from a message channel and forward each consumed message to one or more different message channels depending on a set of conditions.

Spring Integration provides the following routers:

* <<router-implementations-payloadtyperouter,Payload Type Router>>
* <<router-implementations-headervaluerouter,Header Value Router>>
* <<router-implementations-recipientlistrouter,Recipient List Router>>
* <<./xml.adoc#xml-xpath-routing,XPath Router (part of the XML module)>>
* <<router-implementations-exception-router,Error Message Exception Type Router>>
* <<router-namespace,(Generic) Router>>

Router implementations share many configuration parameters.
However, certain differences exist between routers.
Furthermore, the availability of configuration parameters depends on whether routers are used inside or outside of a chain.
In order to provide a quick overview, all available attributes are listed in the two following tables .

The following table shows the configuration parameters available for a router outside of a chain:

.Routers Outside of a Chain
[cols="2,1,1,1,1,1,1", options="header"]
|===
| Attribute
| router
| header value router
| xpath router
| payload type router
| recipient list route
| exception type router

| apply-sequence
a| image::images/tickmark.png[]
a| image::images/tickmark.png[]
a| image::images/tickmark.png[]
a| image::images/tickmark.png[]
a| image::images/tickmark.png[]
a| image::images/tickmark.png[]

| default-output-channel
a| image::images/tickmark.png[]
a| image::images/tickmark.png[]
a| image::images/tickmark.png[]
a| image::images/tickmark.png[]
a| image::images/tickmark.png[]
a| image::images/tickmark.png[]

| resolution-required
a| image::images/tickmark.png[]
a| image::images/tickmark.png[]
a| image::images/tickmark.png[]
a| image::images/tickmark.png[]
a| image::images/tickmark.png[]
a| image::images/tickmark.png[]

| ignore-send-failures
a| image::images/tickmark.png[]
a| image::images/tickmark.png[]
a| image::images/tickmark.png[]
a| image::images/tickmark.png[]
a| image::images/tickmark.png[]
a| image::images/tickmark.png[]

| timeout
a| image::images/tickmark.png[]
a| image::images/tickmark.png[]
a| image::images/tickmark.png[]
a| image::images/tickmark.png[]
a| image::images/tickmark.png[]
a| image::images/tickmark.png[]

| id
a| image::images/tickmark.png[]
a| image::images/tickmark.png[]
a| image::images/tickmark.png[]
a| image::images/tickmark.png[]
a| image::images/tickmark.png[]
a| image::images/tickmark.png[]

| auto-startup
a| image::images/tickmark.png[]
a| image::images/tickmark.png[]
a| image::images/tickmark.png[]
a| image::images/tickmark.png[]
a| image::images/tickmark.png[]
a| image::images/tickmark.png[]

| input-channel
a| image::images/tickmark.png[]
a| image::images/tickmark.png[]
a| image::images/tickmark.png[]
a| image::images/tickmark.png[]
a| image::images/tickmark.png[]
a| image::images/tickmark.png[]

| order
a| image::images/tickmark.png[]
a| image::images/tickmark.png[]
a| image::images/tickmark.png[]
a| image::images/tickmark.png[]
a| image::images/tickmark.png[]
a| image::images/tickmark.png[]

| method
a| image::images/tickmark.png[]
|
|
|
|
|

| ref
a| image::images/tickmark.png[]
|
|
|
|
|

| expression
a| image::images/tickmark.png[]
|
|
|
|
|

| header-name
|
a| image::images/tickmark.png[]
|
|
|
|

| evaluate-as-string
|
|
a| image::images/tickmark.png[]
|
|
|

| xpath-expression-ref
|
|
a| image::images/tickmark.png[]
|
|
|

| converter
|
|
a| image::images/tickmark.png[]
|
|
|
|===


The following table shows the configuration parameters available for a router inside of a chain:

.Routers Inside of a Chain
[cols="2,1,1,1,1,1,1", options="header"]
|===
| Attribute
| router
| header value router
| xpath router
| payload type router
| recipient list router
| exception type router

| apply-sequence
a| image::images/tickmark.png[]
a| image::images/tickmark.png[]
a| image::images/tickmark.png[]
a| image::images/tickmark.png[]
a| image::images/tickmark.png[]
a| image::images/tickmark.png[]

| default-output-channel
a| image::images/tickmark.png[]
a| image::images/tickmark.png[]
a| image::images/tickmark.png[]
a| image::images/tickmark.png[]
a| image::images/tickmark.png[]
a| image::images/tickmark.png[]

| resolution-required
a| image::images/tickmark.png[]
a| image::images/tickmark.png[]
a| image::images/tickmark.png[]
a| image::images/tickmark.png[]
a| image::images/tickmark.png[]
a| image::images/tickmark.png[]

| ignore-send-failures
a| image::images/tickmark.png[]
a| image::images/tickmark.png[]
a| image::images/tickmark.png[]
a| image::images/tickmark.png[]
a| image::images/tickmark.png[]
a| image::images/tickmark.png[]

| timeout
a| image::images/tickmark.png[]
a| image::images/tickmark.png[]
a| image::images/tickmark.png[]
a| image::images/tickmark.png[]
a| image::images/tickmark.png[]
a| image::images/tickmark.png[]

| id
|
|
|
|
|
|

| auto-startup
|
|
|
|
|
|

| input-channel
|
|
|
|
|
|

| order
|
|
|
|
|
|

| method
a| image::images/tickmark.png[]
|
|
|
|
|

| ref
a| image::images/tickmark.png[]
|
|
|
|
|

| expression
a| image::images/tickmark.png[]
|
|
|
|
|

| header-name
|
a| image::images/tickmark.png[]
|
|
|
|

| evaluate-as-string
|
|
a| image::images/tickmark.png[]
|
|
|

| xpath-expression-ref
|
|
a| image::images/tickmark.png[]
|
|
|

| converter
|
|
a| image::images/tickmark.png[]
|
|
|
|===

[IMPORTANT]
=====
As of Spring Integration 2.1, router parameters have been more standardized across all router implementations.
Consequently, a few minor changes may break older Spring Integration based applications.

Since Spring Integration 2.1, the `ignore-channel-name-resolution-failures` attribute is removed in favor of consolidating its behavior with the `resolution-required` attribute.
Also, the `resolution-required` attribute now defaults to `true`.

Prior to these changes, the `resolution-required` attribute defaulted to `false`, causing messages to be silently dropped when no channel was resolved and no `default-output-channel` was set.
The new behavior requires at least one resolved channel and, by default, throws a `MessageDeliveryException` if no channel was determined (or an attempt to send was not successful).

If you do desire to drop messages silently, you can set `default-output-channel="nullChannel"`.
=====

[[router-common-parameters]]
==== Common Router Parameters

This section describes the parameters common to all router parameters (the parameters with all their boxes ticked in the two tables shown earlier in this chapter).

[[router-common-parameters-all]]
===== Inside and Outside of a Chain

The following parameters are valid for all routers inside and outside of chains.

`apply-sequence`::
This attribute specifies whether sequence number and size headers should be added to each message.
This optional attribute defaults to `false`.

`default-output-channel`::
If set, this attribute provides a reference to the channel where messages should be sent if channel resolution fails to return any channels.
If no default output channel is provided, the router throws an exception.
If you would like to silently drop those messages instead, set the default output channel attribute value to `nullChannel`.
+
NOTE: A message is sent only to the `default-output-channel` if `resolution-required` is `false` and the channel is not resolved.

`resolution-required`::
This attribute specifies whether channel names must always be successfully resolved to channel instances that exist.
If set to `true`, a `MessagingException` is raised when the channel cannot be resolved.
Setting this attribute to `false` causes any unresovable channels to be ignored.
This optional attribute defaults to `true`.
+
NOTE: A Message is sent only to the `default-output-channel`, if specified, when `resolution-required` is `false` and the channel is not resolved.

`ignore-send-failures`::
If set to `true`, failures to send to a message channel is ignored.
If set to `false`, a `MessageDeliveryException` is thrown instead, and, if the router resolves more than one channel, any subsequent channels do not receive the message.
+
The exact behavior of this attribute depends on the type of the `Channel` to which the messages are sent.
For example, when using direct channels (single threaded), send failures can be caused by exceptions thrown by components much further downstream.
However, when sending messages to a simple queue channel (asynchronous), the likelihood of an exception to be thrown is rather remote.
+
NOTE: While most routers route to a single channel, they can return more than one channel name.
The `recipient-list-router`, for instance, does exactly that.
If you set this attribute to `true` on a router that only routes to a single channel, any caused exception is swallowed, which usually makes little sense.
In that case, it would be better to catch the exception in an error flow at the flow entry point.
Therefore, setting the `ignore-send-failures` attribute to `true` usually makes more sense when the router implementation returns more than one channel name, because the other channel(s) following the one that fails would still receive the message.
+
This attribute defaults to `false`.

`timeout`::
The `timeout` attribute specifies the maximum amount of time in milliseconds to wait when sending messages to the target Message Channels.
By default, the send operation blocks indefinitely.

[[router-common-parameters-top]]
===== Top-Level (Outside of a Chain)

The following parameters are valid only across all top-level routers that are outside of chains.

`id`::
Identifies the underlying Spring bean definition, which, in the case of routers, is an instance of `EventDrivenConsumer` or `PollingConsumer`, depending on whether the router's `input-channel` is a `SubscribableChannel` or a `PollableChannel`, respectively.
This is an optional attribute.

`auto-startup`::
This "`lifecycle`" attribute signaled whether this component should be started during startup of the application context.
This optional attribute defaults to `true`.

`input-channel`::
The receiving message channel of this endpoint.

`order`::
This attribute defines the order for invocation when this endpoint is connected as a subscriber to a channel.
This is particularly relevant when that channel uses a failover dispatching strategy.
It has no effect when this endpoint itself is a polling consumer for a channel with a queue.

[[router-implementations]]
==== Router Implementations

Since content-based routing often requires some domain-specific logic, most use cases require Spring Integration's options for delegating to POJOs by using either the XML namespace support or annotations.
Both of these are discussed later.
However, we first present a couple of implementations that fulfill common requirements.

[[router-implementations-payloadtyperouter]]
===== `PayloadTypeRouter`

A `PayloadTypeRouter` sends messages to the channel defined by payload-type mappings, as the following example shows:

====
[source,xml]
----
<bean id="payloadTypeRouter"
      class="org.springframework.integration.router.PayloadTypeRouter">
    <property name="channelMapping">
        <map>
            <entry key="java.lang.String" value-ref="stringChannel"/>
            <entry key="java.lang.Integer" value-ref="integerChannel"/>
        </map>
    </property>
</bean>
----
====

Configuration of the `PayloadTypeRouter` is also supported by the namespace provided by Spring Integration (see `<<./configuration.adoc#configuration-namespace,Namespace Support>>`), which essentially simplifies configuration by combining the `<router/>` configuration and its corresponding implementation (defined by using a `<bean/>` element) into a single and more concise configuration element.
The following example shows a `PayloadTypeRouter` configuration that is equivalent to the one above but uses the namespace support:

====
[source,xml]
----
<int:payload-type-router input-channel="routingChannel">
    <int:mapping type="java.lang.String" channel="stringChannel" />
    <int:mapping type="java.lang.Integer" channel="integerChannel" />
</int:payload-type-router>
----
====

The following example shows the equivalent router configured in Java:

====
[source, java]
----
@ServiceActivator(inputChannel = "routingChannel")
@Bean
public PayloadTypeRouter router() {
    PayloadTypeRouter router = new PayloadTypeRouter();
    router.setChannelMapping(String.class.getName(), "stringChannel");
    router.setChannelMapping(Integer.class.getName(), "integerChannel");
    return router;
}
----
====

When using the Java DSL, there are two options.

First, you can define the router object as shown in the preceding example:

[source, java]
----
@Bean
public IntegrationFlow routerFlow1() {
    return IntegrationFlows.from("routingChannel")
            .route(router())
            .get();
}

public PayloadTypeRouter router() {
    PayloadTypeRouter router = new PayloadTypeRouter();
    router.setChannelMapping(String.class.getName(), "stringChannel");
    router.setChannelMapping(Integer.class.getName(), "integerChannel");
    return router;
}
----

Note that the router can be, but does not have to be, a `@Bean`.
The flow registers it if it is not a `@Bean`.

Second, you can define the routing function within the DSL flow itself, as the following example shows:

====
[source, java]
----
@Bean
public IntegrationFlow routerFlow2() {
    return IntegrationFlows.from("routingChannel")
            .<Object, Class<?>>route(Object::getClass, m -> m
                    .channelMapping(String.class, "stringChannel")
                    .channelMapping(Integer.class, "integerChannel"))
            .get();
}
----
====

[[router-implementations-headervaluerouter]]
===== `HeaderValueRouter`

A `HeaderValueRouter` sends Messages to the channel based on the individual header value mappings.
When a `HeaderValueRouter` is created, it is initialized with the name of the header to be evaluated.
The value of the header could be one of two things:

* An arbitrary value
* A channel name

If it is an arbitrary value, additional mappings for these header values to channel names are required.
Otherwise, no additional configuration is needed.

Spring Integration provides a simple namespace-based XML configuration to configure a `HeaderValueRouter`.
The following example demonstrates configuration for the `HeaderValueRouter` when mapping of header values to channels is required:

====
[source,xml]
----
<int:header-value-router input-channel="routingChannel" header-name="testHeader">
    <int:mapping value="someHeaderValue" channel="channelA" />
    <int:mapping value="someOtherHeaderValue" channel="channelB" />
</int:header-value-router>
----
====

During the resolution process, the router defined in the preceding example may encounter channel resolution failures, causing an exception.
If you want to suppress such exceptions and send unresolved messages to the default output channel (identified with the `default-output-channel` attribute) set `resolution-required` to `false`.

Normally, messages for which the header value is not explicitly mapped to a channel are sent to the `default-output-channel`.
However, when the header value is mapped to a channel name but the channel cannot be resolved, setting the `resolution-required` attribute to `false` results in routing such messages to the `default-output-channel`.

IMPORTANT: As of Spring Integration 2.1, the attribute was changed from `ignore-channel-name-resolution-failures` to `resolution-required`.
Attribute `resolution-required` defaults to `true`.

The following example shows the equivalent router configured in Java:

====
[source, java]
----
@ServiceActivator(inputChannel = "routingChannel")
@Bean
public HeaderValueRouter router() {
    HeaderValueRouter router = new HeaderValueRouter("testHeader");
    router.setChannelMapping("someHeaderValue", "channelA");
    router.setChannelMapping("someOtherHeaderValue", "channelB");
    return router;
}
----
====

When using the Java DSL, there are two options.
First, you can define the router object as shown in the preceding example:

====
[source, java]
----
@Bean
public IntegrationFlow routerFlow1() {
    return IntegrationFlows.from("routingChannel")
            .route(router())
            .get();
}

public HeaderValueRouter router() {
    HeaderValueRouter router = new HeaderValueRouter("testHeader");
    router.setChannelMapping("someHeaderValue", "channelA");
    router.setChannelMapping("someOtherHeaderValue", "channelB");
    return router;
}
----
====

Note that the router can be, but does not have to be, a `@Bean`.
The flow registers it if it is not a `@Bean`.

Second, you can define the routing function within the DSL flow itself, as the following example shows:

====
[source, java]
----
@Bean
public IntegrationFlow routerFlow2() {
    return IntegrationFlows.from("routingChannel")
            .<Message<?>, String>route(m -> m.getHeaders().get("testHeader", String.class), m -> m
                    .channelMapping("someHeaderValue", "channelA")
                    .channelMapping("someOtherHeaderValue", "channelB"),
                e -> e.id("headerValueRouter"))
            .get();
}
----
====

Configuration where mapping of header values to channel names is not required, because header values themselves represent channel names.
The following example shows a router that does not require mapping of header values to channel names:

====
[source,xml]
----
<int:header-value-router input-channel="routingChannel" header-name="testHeader"/>
----
====

[NOTE]
=====
Since Spring Integration 2.1, the behavior of resolving channels is more explicit.
For example, if you omit the `default-output-channel` attribute, the router was unable to resolve at least one valid channel, and any channel name resolution failures were ignored by setting `resolution-required` to `false`, then a `MessageDeliveryException` is thrown.

Basically, by default, the router must be able to route messages successfully to at least one channel.
If you really want to drop messages, you must also have `default-output-channel` set to `nullChannel`.
=====

[[router-implementations-recipientlistrouter]]
===== `RecipientListRouter`

A `RecipientListRouter` sends each received message to a statically defined list of message channels.
The following example creates a `RecipientListRouter`:

====
[source,xml]
----
<bean id="recipientListRouter"
      class="org.springframework.integration.router.RecipientListRouter">
    <property name="channels">
        <list>
            <ref bean="channel1"/>
            <ref bean="channel2"/>
            <ref bean="channel3"/>
        </list>
    </property>
</bean>
----
====

Spring Integration also provides namespace support for the `RecipientListRouter` configuration (see <<./configuration.adoc#configuration-namespace,Namespace Support>>) as the following example shows:

====
[source,xml]
----
<int:recipient-list-router id="customRouter" input-channel="routingChannel"
        timeout="1234"
        ignore-send-failures="true"
        apply-sequence="true">
  <int:recipient channel="channel1"/>
  <int:recipient channel="channel2"/>
</int:recipient-list-router>
----
====

The following example shows the equivalent router configured in Java:

====
[source, java]
----
@ServiceActivator(inputChannel = "routingChannel")
@Bean
public RecipientListRouter router() {
    RecipientListRouter router = new RecipientListRouter();
    router.setSendTimeout(1_234L);
    router.setIgnoreSendFailures(true);
    router.setApplySequence(true);
    router.addRecipient("channel1");
    router.addRecipient("channel2");
    router.addRecipient("channel3");
    return router;
}
----
====

The following example shows the equivalent router configured by using the Java DSL:

====
[source, java]
----
@Bean
public IntegrationFlow routerFlow() {
    return IntegrationFlows.from("routingChannel")
            .routeToRecipients(r -> r
                    .applySequence(true)
                    .ignoreSendFailures(true)
                    .recipient("channel1")
                    .recipient("channel2")
                    .recipient("channel3")
                    .sendTimeout(1_234L))
            .get();
}
----
====

NOTE: The 'apply-sequence' flag here has the same effect as it does for a publish-subscribe-channel, and, as with a publish-subscribe-channel, it is disabled by default on the `recipient-list-router`.
See <<./channel.adoc#channel-configuration-pubsubchannel,`PublishSubscribeChannel` Configuration>> for more information.

Another convenient option when configuring a `RecipientListRouter` is to use Spring Expression Language (SpEL) support as selectors for individual recipient channels.
Doing so is similar to using a filter at the beginning of a 'chain' to act as a "`selective consumer`".
However, in this case, it is all combined rather concisely into the router's configuration, as the following example shows:

[source,xml]
----
<int:recipient-list-router id="customRouter" input-channel="routingChannel">
    <int:recipient channel="channel1" selector-expression="payload.equals('foo')"/>
    <int:recipient channel="channel2" selector-expression="headers.containsKey('bar')"/>
</int:recipient-list-router>
----

In the preceding configuration, a SpEL expression identified by the `selector-expression` attribute is evaluated to determine whether this recipient should be included in the recipient list for a given input message.
The evaluation result of the expression must be a boolean.
If this attribute is not defined, the channel is always among the list of recipients.

[[recipient-list-router-management]]
===== `RecipientListRouterManagement`

Starting with version 4.1, the `RecipientListRouter` provides several operations to manipulate recipients dynamically at runtime.
These management operations are presented by `RecipientListRouterManagement` through the `@ManagedResource` annotation.
They are available by using <<./control-bus.adoc#control-bus,Control Bus>> as well as by using JMX, as the following example shows:

====
[source,xml]
----
<control-bus input-channel="controlBus"/>

<recipient-list-router id="simpleRouter" input-channel="routingChannelA">
   <recipient channel="channel1"/>
</recipient-list-router>

<channel id="channel2"/>
----

[source,java]
----
messagingTemplate.convertAndSend(controlBus, "@'simpleRouter.handler'.addRecipient('channel2')");
----
====

From the application start up the `simpleRouter`, has only one `channel1` recipient.
But after the `addRecipient` command, `channel2` recipient is added.
It is a "`registering an interest in something that is part of the message`" use case, when we may be interested in messages from the router at some time period, so we are subscribing to the the `recipient-list-router` and, at some point, decide to unsubscribe.

Because of the runtime management operation for the `<recipient-list-router>`, it can be configured without any `<recipient>` from the start.
In this case, the behavior of `RecipientListRouter` is the same when there is no one matching recipient for the message.
If `defaultOutputChannel` is configured, the message is sent there.
Otherwise the `MessageDeliveryException` is thrown.

[[router-implementations-xpath-router]]
===== XPath Router

The XPath Router is part of the XML Module.
See <<./xml.adoc#xml-xpath-routing,Routing XML Messages with XPath>>.

[[router-implementations-exception-router]]
===== Routing and Error Handling

Spring Integration also provides a special type-based router called `ErrorMessageExceptionTypeRouter` for routing error messages (defined as messages whose `payload` is a `Throwable` instance).
`ErrorMessageExceptionTypeRouter` is similar to the `PayloadTypeRouter`.
In fact, they are almost identical.
The only difference is that, while `PayloadTypeRouter` navigates the instance hierarchy of a payload instance (for example, `payload.getClass().getSuperclass()`) to find the most specific type and channel mappings, the `ErrorMessageExceptionTypeRouter` navigates the hierarchy of 'exception causes' (for example, `payload.getCause()`) to find the most specific `Throwable` type or channel mappings and uses `mappingClass.isInstance(cause)` to match the `cause` to the class or any super class.

IMPORTANT: The channel mapping order in this case matters.
So, if there is a requirement to get mapping for an `IllegalArgumentException`, but not a `RuntimeException`, the last one must be configured on router first.

NOTE: Since version 4.3 the `ErrorMessageExceptionTypeRouter` loads all mapping classes during the initialization phase to fail-fast for a `ClassNotFoundException`.

The following example shows a sample configuration for `ErrorMessageExceptionTypeRouter`:

[source,xml]
----
<int:exception-type-router input-channel="inputChannel"
                           default-output-channel="defaultChannel">
    <int:mapping exception-type="java.lang.IllegalArgumentException"
                 channel="illegalChannel"/>
    <int:mapping exception-type="java.lang.NullPointerException"
                 channel="npeChannel"/>
</int:exception-type-router>

<int:channel id="illegalChannel" />
<int:channel id="npeChannel" />
----

[[router-namespace]]
==== Configuring a Generic Router

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).

===== Configuring a Content-based Router with XML

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:

====
[source,xml]
----
<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"/>
----
====

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:

====
[source,xml]
----
<int:router input-channel="input" ref="somePojo" method="someMethod"/>
----
====

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:

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

NOTE: 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.

IMPORTANT: 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.

The following example shows the equivalent router configured in Java:

====
[source, java]
----
@Bean
@Router(inputChannel = "routingChannel")
public AbstractMessageRouter myCustomRouter() {
    return new AbstractMessageRouter() {

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

    };
}
----
====

The following example shows the equivalent router configured by using the Java DSL:

====
[source, java]
----
@Bean
public IntegrationFlow routerFlow() {
    return IntegrationFlows.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:

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

[[router-spel]]
==== Routers and the Spring Expression Language (SpEL)

Sometimes, the routing logic may be simple, and writing a separate class for it and configuring it as a bean may seem like overkill.
As of Spring Integration 2.0, we offer an alternative that lets you use SpEL to implement simple computations that previously required a custom POJO router.

NOTE: For more information about the Spring Expression Language, see the https://docs.spring.io/spring/docs/current/spring-framework-reference/core.html#expressions[relevant chapter in the Spring Framework Reference Guide]:

Generally, a SpEL expression is evaluated and its result is mapped to a channel, as the following example shows:

====
[source,xml]
----
<int:router input-channel="inChannel" expression="payload.paymentType">
    <int:mapping value="CASH" channel="cashPaymentChannel"/>
    <int:mapping value="CREDIT" channel="authorizePaymentChannel"/>
    <int:mapping value="DEBIT" channel="authorizePaymentChannel"/>
</int:router>
----
====

The following example shows the equivalent router configured in Java:

====
[source, java]
----
@Router(inputChannel = "routingChannel")
@Bean
public ExpressionEvaluatingRouter router() {
    ExpressionEvaluatingRouter router = new ExpressionEvaluatingRouter("payload.paymentType");
    router.setChannelMapping("CASH", "cashPaymentChannel");
    router.setChannelMapping("CREDIT", "authorizePaymentChannel");
    router.setChannelMapping("DEBIT", "authorizePaymentChannel");
    return router;
}
----
====

The following example shows the equivalent router configured in the Java DSL:

====
[source, java]
----
@Bean
public IntegrationFlow routerFlow() {
    return IntegrationFlows.from("routingChannel")
        .route("payload.paymentType", r -> r
            .channelMapping("CASH", "cashPaymentChannel")
            .channelMapping("CREDIT", "authorizePaymentChannel")
            .channelMapping("DEBIT", "authorizePaymentChannel"))
        .get();
}
----
====

To simplify things even more, the SpEL expression may evaluate to a channel name, as the following expression shows:

[source,xml]
----
<int:router input-channel="inChannel" expression="payload + 'Channel'"/>
----

In the preceding configuration, the result channel is computed by the SpEL expression, which concatenates the value of the `payload` with the literal `String`, 'Channel'.

Another virtue of SpEL for configuring routers is that an expression can return a `Collection`, effectively making every `<router>` a recipient list router.
Whenever the expression returns multiple channel values, the message is forwarded to each channel.
The following example shows such an expression:

====
[source,xml]
----
<int:router input-channel="inChannel" expression="headers.channels"/>
----
====

In the above configuration, if the message includes a header with a name of 'channels' and the value of that header is a `List` of channel names, the message is sent to each channel in the list.
You may also find collection projection and collection selection expressions useful when you need to select multiple channels.
For further information, see:

* https://docs.spring.io/spring-framework/docs/current/spring-framework-reference/core.html#expressions-collection-projection[Collection Projection]
* https://docs.spring.io/spring-framework/docs/current/spring-framework-reference/core.html#expressions-collection-selection[Collection Selection]

[[router-annotation]]
===== Configuring a Router with Annotations

When using `@Router` to annotate a method, the method may return either a `MessageChannel` or a `String` type.
In the latter case, the endpoint resolves the channel name as it does for the default output channel.
Additionally, the method may return either a single value or a collection.
If a collection is returned, the reply message is sent to multiple channels.
To summarize, the following method signatures are all valid:

====
[source,java]
----
@Router
public MessageChannel route(Message message) {...}

@Router
public List<MessageChannel> route(Message message) {...}

@Router
public String route(Foo payload) {...}

@Router
public List<String> route(Foo payload) {...}
----
====

In addition to payload-based routing, a message may be routed based on metadata available within the message header as either a property or an attribute.
In this case, a method annotated with `@Router` may include a parameter annotated with `@Header`, which is mapped to a header value as the following example shows and documented in <<./configuration.adoc#annotations,Annotation Support>>:

====
[source,java]
----
@Router
public List<String> route(@Header("orderStatus") OrderStatus status)
----
====

NOTE: For routing of XML-based Messages, including XPath support, see <<./xml.adoc#xml,XML Support - Dealing with XML Payloads>>.

See also <<./dsl.adoc#java-dsl-routers,Message Routers>> in the Java DSL chapter for more information about router configuration.

[[dynamic-routers]]
==== Dynamic Routers

Spring Integration provides quite a few different router configurations for common content-based routing use cases as well as the option of implementing custom routers as POJOs.
For example, `PayloadTypeRouter` provides a simple way to configure a router that computes channels based on the payload type of the incoming message while `HeaderValueRouter` provides the same convenience in configuring a router that computes channels by evaluating the value of a particular message Header.
There are also expression-based (SpEL) routers, in which the channel is determined based on evaluating an expression.
All of these type of routers exhibit some dynamic characteristics.

However, these routers all require static configuration.
Even in the case of expression-based routers, the expression itself is defined as part of the router configuration, which means that the same expression operating on the same value always results in the computation of the same channel.
This is acceptable in most cases, since such routes are well defined and therefore predictable.
But there are times when we need to change router configurations dynamically so that message flows may be routed to a different channel.

For example, you might want to bring down some part of your system for maintenance and temporarily re-reroute messages to a different message flow.
As another example, you may want to introduce more granularity to your message flow by adding another route to handle a more concrete type of `java.lang.Number` (in the case of `PayloadTypeRouter`).

Unfortunately, with static router configuration to accomplish either of those goals, you would have to bring down your entire application, change the configuration of the router (change routes), and bring the application back up.
This is obviously not a solution anyone wants.

The https://www.enterpriseintegrationpatterns.com/DynamicRouter.html[dynamic router] pattern describes the mechanisms by which you can change or configure routers dynamically without bringing down the system or individual routers. 

Before we get into the specifics of how Spring Integration supports dynamic routing, we need to consider the typical flow of a router:

. Compute a channel identifier, which is a value calculated by the router once it receives the message.
Typically, it is a String or an instance of the actual `MessageChannel`.
. Resolve the channel identifier to a channel name.
We describe specifics of this process later in this section.
. Resolve the channel name to the actual `MessageChannel`

There is not much that can be done with regard to dynamic routing if Step 1 results in the actual instance of the `MessageChannel`, because the `MessageChannel` is the final product of any router's job.
However, if the first step results in a channel identifier that is not an instance of `MessageChannel`, you have quite a few possible ways to influence the process of deriving the `MessageChannel`.
Consider the following example of a payload type router:

====
[source,xml]
----
<int:payload-type-router input-channel="routingChannel">
    <int:mapping type="java.lang.String"  channel="channel1" />
    <int:mapping type="java.lang.Integer" channel="channel2" />
</int:payload-type-router>
----
====

Within the context of a payload type router, the three steps mentioned earlier would be realized as follows:

. Compute a channel identifier that is the fully qualified name of the payload type (for example, `java.lang.String`).
. Resolve the channel identifier to a channel name, where the result of the previous step is used to select the appropriate value from the payload type mapping defined in the `mapping` element.
. Resolve the channel name to the actual instance of the `MessageChannel` as a reference to a bean within the application context (which is hopefully a `MessageChannel`) identified by the result of the previous step.

In other words, each step feeds the next step until the process completes.


Now consider an example of a header value router:

====
[source,xml]
----
<int:header-value-router input-channel="inputChannel" header-name="testHeader">
    <int:mapping value="foo" channel="fooChannel" />
    <int:mapping value="bar" channel="barChannel" />
</int:header-value-router>
----
====

Now we can consider how the three steps work for a header value router:

. Compute a channel identifier that is the value of the header identified by the `header-name` attribute.
. Resolve the channel identifier a to channel name, where the result of the previous step is used to select the appropriate value from the general mapping defined in the `mapping` element.
. Resolve the channel name to the actual instance of the `MessageChannel` as a reference to a bean within the application context (which is hopefully a `MessageChannel`) identified by the result of the previous step.

The preceding two configurations of two different router types look almost identical.
However, if you look at the alternate configuration of the `HeaderValueRouter` we clearly see that there is no `mapping` sub element, as the following listing shows:

====
[source,xml]
----
<int:header-value-router input-channel="inputChannel" header-name="testHeader">
----
====

However, the configuration is still perfectly valid.
So the natural question is what about the mapping in the second step?

The second step is now optional.
If `mapping` is not defined, then the channel identifier value computed in the first step is automatically treated as the `channel name`, which is now resolved to the actual `MessageChannel`, as in the third step. 
What it also means is that the second step is one of the key steps to providing dynamic characteristics to the routers, since it introduces a process that lets you change the way channel identifier resolves to the channel name, thus influencing the process of determining the final instance of the `MessageChannel` from the initial channel identifier. 

For example, in the preceding configuration, assume that the `testHeader` value is 'kermit', which is now a channel identifier (the first step).
Since there is no mapping in this router, resolving this channel identifier to a channel name (the second step) is impossible and this channel identifier is now treated as the channel name.
However, what if there was a mapping but for a different value?
The end result would still be the same, because, if a new value cannot be determined through the process of resolving the channel identifier to a channel name, the channel identifier becomes the channel name.

All that is left is for the third step to resolve the channel name ('kermit') to an actual instance of the `MessageChannel` identified by this name.
That basically involves a bean lookup for the provided name.
Now all messages that contain the header-value pair as `testHeader=kermit` are going to be routed to a `MessageChannel` whose bean name (its `id`) is 'kermit'.

But what if you want to route these messages to the 'simpson' channel? Obviously changing a static configuration works, but doing so also requires bringing your system down.
However, if you had access to the channel identifier map, you could introduce a new mapping where the header-value pair is now `kermit=simpson`, thus letting the second step treat 'kermit' as a channel identifier while resolving it to 'simpson' as the channel name.

The same obviously applies for `PayloadTypeRouter`, where you can now remap or remove a particular payload type mapping.
In fact, it applies to every other router, including expression-based routers, since their computed values now have a chance to go through the second step to be resolved to the actual `channel name`.

Any router that is a subclass of the `AbstractMappingMessageRouter` (which includes most framework-defined routers) is a dynamic router, because the `channelMapping` is defined at the `AbstractMappingMessageRouter` level.
That map's setter method is exposed as a public method along with the 'setChannelMapping' and 'removeChannelMapping' methods.
These let you  change, add, and remove router mappings at runtime, as long as you have a reference to the router itself.
It also means that you could expose these same configuration options through JMX (see <<./jmx.adoc#jmx,JMX Support>>) or the Spring Integration control bus (see <<./control-bus.adoc#control-bus,Control Bus>>) functionality. 

IMPORTANT: Falling back to the channel key as the channel name is flexible and convenient.
However, if you don't trust the message creator, a malicious actor (who has knowledge of the system) could create a message that is routed to an unexpected channel.
For example, if the key is set to the channel name of the router's input channel, such a message would be routed back to the router, eventually resulting in a stack overflow error.
You may therefore wish to disable this feature (set the `channelKeyFallback` property to `false`), and change the mappings instead if needed.

[[dynamic-routers-control-bus]]
===== Manage Router Mappings using the Control Bus

One way to manage the router mappings is through the https://www.enterpriseintegrationpatterns.com/ControlBus.html[control bus] pattern, which exposes a control channel to which you can send control messages to manage and monitor Spring Integration components, including routers.

NOTE: For more information about the control bus, see <<./control-bus.adoc#control-bus,Control Bus>>.

Typically, you would send a control message asking to invoke a particular operation on a particular managed component (such as a
router).
The following managed operations (methods) are specific to changing the router resolution process:

* `public void setChannelMapping(String key, String channelName)`: Lets you add a new or modify an existing mapping between `channel identifier` and `channel name`
* `public void removeChannelMapping(String key)`: Lets you remove a particular channel mapping, thus disconnecting the relationship between `channel identifier` and `channel name`

Note that these methods can be used for simple changes (such as updating a single route or adding or removing a route).
However, if you want to remove one route and add another, the updates are not atomic.
This means that the routing table may be in an indeterminate state between the updates.
Starting with version 4.0, you can now use the control bus to update the entire routing table atomically.
The following methods let you do so:

* `public Map<String, String>getChannelMappings()`: Returns the current mappings.
* `public void replaceChannelMappings(Properties channelMappings)`: Updates the mappings.
Note that the `channelMappings` parameter is a `Properties` object.
This arrangement lets a control bus command use the built-in `StringToPropertiesConverter`, as the following example shows:

====
[source]
----
"@'router.handler'.replaceChannelMappings('foo=qux \n baz=bar')"
----
====

Note that each mapping is separated by a newline character (`\n`).
For programmatic changes to the map, we recommend that you use the `setChannelMappings` method, due to type-safety concerns.
`replaceChannelMappings` ignores keys or values that are not `String` objects.

[[dynamic-routers-jmx]]
===== Manage Router Mappings by Using JMX

You can also use Spring's JMX support to expose a router instance and then use your favorite JMX client (for example, JConsole) to manage those operations (methods) for changing the router's configuration.

NOTE: For more information about Spring Integration's JMX support, see <<./jmx.adoc#jmx,JMX Support>>.

[[routing-slip]]
===== Routing Slip

Starting with version 4.1, Spring Integration provides an implementation of the https://www.enterpriseintegrationpatterns.com/RoutingTable.html[routing slip] enterprise integration pattern.
It is implemented as a `routingSlip` message header, which is used to determine the next channel in `AbstractMessageProducingHandler` instances, when an `outputChannel` is not specified for the endpoint.
This pattern is useful in complex, dynamic cases, when it can become difficult to configure multiple routers to determine message flow.
When a message arrives at an endpoint that has no `output-channel`, the `routingSlip` is consulted to determine the next channel to which the message is sent.
When the routing slip is exhausted, normal `replyChannel` processing resumes.

Configuration for the routing slip is presented as a `HeaderEnricher` option -- a semicolon-separated routing slip that contains `path` entries, as the following example shows:

====
[source,xml]
----
<util:properties id="properties">
    <beans:prop key="myRoutePath1">channel1</beans:prop>
    <beans:prop key="myRoutePath2">request.headers[myRoutingSlipChannel]</beans:prop>
</util:properties>

<context:property-placeholder properties-ref="properties"/>

<header-enricher input-channel="input" output-channel="process">
    <routing-slip
        value="${myRoutePath1}; @routingSlipRoutingPojo.get(request, reply);
               routingSlipRoutingStrategy; ${myRoutePath2}; finishChannel"/>
</header-enricher>
----
====

The preceding example has:

* A `<context:property-placeholder>` configuration to demonstrate that the entries in the routing slip `path` can be specified as resolvable keys.
* The `<header-enricher>` `<routing-slip>` sub-element is used to populate the `RoutingSlipHeaderValueMessageProcessor` to the `HeaderEnricher` handler.
* The `RoutingSlipHeaderValueMessageProcessor` accepts a `String` array of resolved routing slip `path` entries and returns (from `processMessage()`) a `singletonMap` with the `path` as `key` and `0` as initial `routingSlipIndex`.

Routing Slip `path` entries can contain `MessageChannel` bean names, `RoutingSlipRouteStrategy` bean names, and Spring expressions (SpEL).
The `RoutingSlipHeaderValueMessageProcessor` checks each routing slip `path` entry against the `BeanFactory` on the first `processMessage` invocation.
It converts entries (which are not bean names in the application context) to `ExpressionEvaluatingRoutingSlipRouteStrategy` instances.
`RoutingSlipRouteStrategy` entries are invoked multiple times, until they return null or an empty `String`.

Since the routing slip is involved in the `getOutputChannel` process, we have a request-reply context.
The `RoutingSlipRouteStrategy` has been introduced to determine the next `outputChannel` that uses the `requestMessage` and the `reply` object.
An implementation of this strategy should be registered as a bean in the application context, and its bean name is used in the routing slip `path`.
The `ExpressionEvaluatingRoutingSlipRouteStrategy` implementation is provided.
It accepts a SpEL expression and an internal `ExpressionEvaluatingRoutingSlipRouteStrategy.RequestAndReply` object is used as the root object of the evaluation context.
This is to avoid the overhead of `EvaluationContext` creation for each `ExpressionEvaluatingRoutingSlipRouteStrategy.getNextPath()` invocation.
It is a simple Java bean with two properties: `Message<?> request` and `Object reply`.
With this expression implementation, we can specify routing slip `path` entries by using SpEL (for example, `@routingSlipRoutingPojo.get(request, reply)` and `request.headers[myRoutingSlipChannel]`) and avoid defining a bean for the `RoutingSlipRouteStrategy`.

NOTE: The `requestMessage` argument is always a `Message<?>`.
Depending on context, the reply object may be a `Message<?>`, an `AbstractIntegrationMessageBuilder`, or an arbitrary application domain object (when, for example, it is returned by a POJO method invoked by a service activator).
In the first two cases, the usual `Message` properties (`payload` and `headers`) are available when using SpEL (or a Java implementation).
For an arbitrary domain object, these properties are not available.
For this reason, be careful when you use routing slips in conjunction with POJO methods if the result is used to determine the next path.

IMPORTANT: If a routing slip is involved in a distributed environment, we recommend not using inline expressions for the Routing Slip `path`.
This recommendation applies to distributed environments such as cross-JVM applications, using a `request-reply` through a message broker (such as<<./amqp.adoc#amqp,AMQP Support>> or <<./jms.adoc#jms,JMS Support>>), or using a persistent `MessageStore` (<<./message-store.adoc#message-store,Message Store>>) in the integration flow.
The framework uses `RoutingSlipHeaderValueMessageProcessor` to convert them to `ExpressionEvaluatingRoutingSlipRouteStrategy` objects, and they are used in the `routingSlip` message header.
Since this class is not `Serializable` (it cannot be, because it depends on the `BeanFactory`), the entire `Message` becomes non-serializable and, in any distributed operation, we end up with a `NotSerializableException`.
To overcome this limitation, register an `ExpressionEvaluatingRoutingSlipRouteStrategy` bean with the desired SpEL and use its bean name in the routing slip `path` configuration.

For Java configuration, you can add a `RoutingSlipHeaderValueMessageProcessor` instance to the `HeaderEnricher` bean definition, as the following example shows:

====
[source,java]
----
@Bean
@Transformer(inputChannel = "routingSlipHeaderChannel")
public HeaderEnricher headerEnricher() {
    return new HeaderEnricher(Collections.singletonMap(IntegrationMessageHeaderAccessor.ROUTING_SLIP,
            new RoutingSlipHeaderValueMessageProcessor("myRoutePath1",
                                                       "@routingSlipRoutingPojo.get(request, reply)",
                                                       "routingSlipRoutingStrategy",
                                                       "request.headers[myRoutingSlipChannel]",
                                                       "finishChannel")));
}
----
====

The routing slip algorithm works as follows when an endpoint produces a reply and no `outputChannel` has been defined:

* The `routingSlipIndex` is used to get a value from the routing slip `path` list.
* If the value from `routingSlipIndex` is `String`, it is used to get a bean from `BeanFactory`.
* If a returned bean is an instance of `MessageChannel`, it is used as the next `outputChannel` and the `routingSlipIndex` is incremented in the reply message header (the routing slip `path` entries remain unchanged).
* If a returned bean is an instance of `RoutingSlipRouteStrategy` and its `getNextPath` does not return an empty `String`, that result is used as a bean name for the next `outputChannel`.
The `routingSlipIndex` remains unchanged.
* If `RoutingSlipRouteStrategy.getNextPath` returns an empty `String` or `null`, the `routingSlipIndex` is incremented and the `getOutputChannelFromRoutingSlip` is invoked recursively for the next Routing Slip `path` item.
* If the next routing slip `path` entry is not a `String`, it must be an instance of `RoutingSlipRouteStrategy`.
* When the `routingSlipIndex` exceeds the size of the routing slip `path` list, the algorithm moves to the default behavior for the standard `replyChannel` header.

[[process-manager]]
==== Process Manager Enterprise Integration Pattern

Enterprise integration patterns include the https://www.enterpriseintegrationpatterns.com/ProcessManager.html[process manager] pattern.
You can now easily implement this pattern by using custom process manager logic encapsulated in a `RoutingSlipRouteStrategy` within the routing slip.
In addition to a bean name, the `RoutingSlipRouteStrategy` can return any `MessageChannel` object, and there is no requirement that this `MessageChannel` instance be a bean in the application context.
This way, we can provide powerful dynamic routing logic when there is no way to predict which channel should be used.
A `MessageChannel` can be created within the `RoutingSlipRouteStrategy` and returned.
A `FixedSubscriberChannel` with an associated `MessageHandler` implementation is a good combination for such cases.
For example, you can route to a https://projectreactor.io/docs/core/release/reference/#getting-started[Reactive Streams], as the following example shows:

====
[source,java]
----
@Bean
public PollableChannel resultsChannel() {
    return new QueueChannel();
}
@Bean
public RoutingSlipRouteStrategy routeStrategy() {
    return (requestMessage, reply) -> requestMessage.getPayload() instanceof String
            ? new FixedSubscriberChannel(m ->
            Mono.just((String) m.getPayload())
                    .map(String::toUpperCase)
                    .subscribe(v -> messagingTemplate().convertAndSend(resultsChannel(), v)))
            : new FixedSubscriberChannel(m ->
            Mono.just((Integer) m.getPayload())
                    .map(v -> v * 2)
                    .subscribe(v -> messagingTemplate().convertAndSend(resultsChannel(), v)));
}
----
====
