- Apache Camel Developer's Cookbook
- Scott Cranton Jakub Korab
- 747字
- 2025-02-24 23:14:00
Content Based Routing
When you need to route messages based on the content of the message, and/or based on the headers or properties associated with the message, using Camel's Content Based Router EIP is a great way to do that.

Content Based Routing and Filtering are very similar. A Content Based Router has multiple predicates, and the contained steps are performed on the first predicate that the message matches, or the optional otherwise
statement if none matches (similar to an if () {..} else if () {..} else {..}
statement in Java).
Camel's Filter EIP tests against a single predicate, executing the contained processing steps only if the message matches that predicate. The equivalent of a Filter in Java would be a single if
statement.
In this recipe, we will see how to use a Content Based Router to route a message to one of the several destinations based on the content (the body) of the message.
Getting ready
The Java code for this recipe is located in the org.camelcookbook.routing.contentbasedrouter
package. The Spring XML files are located under src/main/resources/META-INF/spring
and prefixed with contentBasedRouter
.
How to do it...
You need to use the choice
DSL statement with one or more when
statements, with their associated predicate tests, to see if the message should be routed down their path, and an optional otherwise
statement that will catch all the messages that do not match any other when
predicates.
- Within your route, create a
choice
statement with at least onewhen
statement. Eachwhen
statement must start with a predicate statement followed by one or more processor steps (for example,<to uri="..."/>
).In the XML DSL, this is written as:
<choice> <when> <simple>${body} contains 'Camel'</simple> <to uri="mock:camel"/> <log message="Camel ${body}"/> </when> <!-- ... --> </choice>
In the Java DSL, this is expressed as:
.choice() .when() .simple("${body} contains 'Camel'") .to("mock:camel") .log("Camel ${body}") //... .end()
Note
In the Java DSL, you need to end the
choice
statement explicitly with a call toend()
if you want to have further steps run after the Content Based Router is complete. Theend()
statement is like the closing}
of a Javaif
statement–it lets the routing engine know that you are done with the Content Based Router instructions. - Add an
otherwise
statement to handle all of the messages that do not match any of yourwhen
predicates. Anotherwise
statement includes one or more steps:In the XML DSL, this is written as:
<choice> <!-- ... --> <otherwise> <to uri="mock:other"/> <log message="Other ${body}"/> </otherwise> </choice>
In the Java DSL, the same thing is written as follows:
.choice() //... .otherwise() .to("mock:other") .log("Other ${body}") .end()
How it works...
A Content Based Router depends on Camel's Predicate capabilities. The preceding example uses Camel's Simple Expression Language. The Simple Expression Language provides a robust set of operators that can work on all of the data contained within the exchange (message, headers, and properties). Each when
element requires one predicate, which can be any one of the many built-in Camel Expression Languages, including any one of the POJO (Plain Old Java Object) methods that returns a boolean
value.
The message is routed to the first when
predicate that matches, in other words, returns true
. The message will then be routed to the one or more processor steps specified after the when
predicate's expression, by default executing multiple processors as a Pipeline, that is, in sequence. If the message does not match any of the when
predicates, it will be routed to the otherwise
block, if specified.
After routing the message to the first matching when
predicate, or the otherwise
statement if there are no matches, it will route to the next processor specified (if any) after the choice
statement.
There's more...
If you want to nest a Content Based Router within another Content Based Router, the inner choice
statement should be defined in its own route to help with code clarity:
from("direct:start") .choice() .when() .simple("${body} contains '<xml>'") .to("direct:processXml") .otherwise() .to("direct:processPlainText") .end(); from("direct:processXml") .choice() .when() .xpath("/order[@units > 100]") .to("direct:priorityXmlOrder") .otherwise() .to("direct:normalXmlOrder") .end();
If you are routing within the when
or otherwise
statements to other EIP patterns, such as Load Balancer or Splitter that specify a Pipeline (sequence) of processors and finish their list of steps with an end()
statement, the list of steps should instead be terminated with endChoice()
statement. This works around the Java language's inability to maintain the nested context properly, and explicitly returns control from the nested EIP back to the containing choice
statement:
.choice() .when().simple("${body} contains 'Camel'") .to("mock:camel") .loadBalance() .to("mock:a") .to("mock:b") .endChoice() .log("Camel ${body}") .otherwise() .to("mock:other") .log("Other ${body}") .end()
See also
- Content Based Router: http://camel.apache.org/content-based-router.html
- Predicate: http://camel.apache.org/predicate.html
endChoice
: http://camel.apache.org/why-can-i-not-use-when-or-otherwise-in-a-java-camel-route.html