Routing

A flow can end by handing its Exchange on to other flows or channels chosen at runtime, instead of a fixed toSink(…​). Two constructs do this: toRoute(…​), which picks destinations with expressions, and toRecipientList(…​), which is deprecated.

Expression-based routing

toRoute(…​) evaluates a list of expressions in order and sends the message to the destinations of the first one that is true.

.toRoute(route -> route.dynamic()
    .when("Headers['type'] == 'PAYMENT'").then("queue://payment-flow")               (1)
    .when("Headers['type'] == 'REFUND'").then("queue://refund-flow", "slf4j://audit") (2)
    .otherwise("queue://default-flow")                                                (3)
    .end()                                                                            (4)
)
1 .when(expression) is a boolean expression (see Expressions) and .then(…​) the destination reached when it is true.
2 .then(…​) accepts several destinations: the message is sent to all of them, each receiving its own copy of the Exchange.
3 .otherwise(…​) is the fallback when no expression is true. Without it, a message that matches nothing fails like a failed step, and is handled by the flow’s error handling.
4 .end() closes the routing table.

A destination is a URL: queue://<queue name> reaches an internal flow (the queue its fromSource("queue://…​") reads), any other channel adapter protocol reaches an external system. A bare name is rejected when the flow is defined.

Destinations computed per message

A destination may contain a #{…​} expression, evaluated against each message with Payload and Headers available:

.toRoute(route -> route.dynamic()
    .when("Payload != null").then("queue://#{Headers['region']}-orders")
    .end()
)
#{…​} is resolved for each message when it is routed. The ${…​} property placeholders of the Spring integration are not resolved in routing destinations - see Endpoint URL Property Placeholders.

Recipient List

The Recipient List pattern sends the message to several destinations at once. For a fixed set of destinations, or a set chosen by an expression, toRoute(…​) above already does this: pass several destinations to .then(…​).

The dedicated toRecipientList(…​) construct is deprecated:

.toRecipientList(list -> list
    .toRecipients("queue://flow-a", "queue://flow-b")            (1)
    .when("Headers['audit'] == 'true'").toRecipient("slf4j://audit-logger")  (2)
    .end())
1 Recipients that always receive the message.
2 A recipient added only when the expression is true.

Prefer toRoute(route → route.dynamic()…​) for new flows.