Camel is a first citizen in Spring Boot application. In this tutorial we will learn how to bootstrap a Camel Route from within a Spring Boot REST application.
Spring Boot provides out of the box support for Camel with starters for most Camel components. Besides, the auto-configuration of the Camel context is able to auto-detect any Camel routes available in the Spring context. Let’s start from the configuration required and then we will add an example Camel Route and a Spring Boot controller.
Setting up a Spring Boot application with Camel
Firstly, we will set up our application. The simplest way to do that, is via Spring Boot Camel archetype:
mvn archetype:generate -DgroupId="sample.camel" \ -DartifactId="reset-producer" \ -DarchetypeGroupId="org.apache.camel.archetypes" \ -DarchetypeArtifactId="camel-archetype-spring-boot" \ -DinteractiveMode=false
Next, let’s have a look at our project structure:
src ├── main │ ├── java │ │ └── sample │ │ └── camel │ │ ├── MySpringBean.java │ │ ├── MySpringBootApplication.java │ │ └── MySpringBootRouter.java │ └── resources │ ├── application.properties │ └── META-INF │ ├── LICENSE.txt │ └── NOTICE.txt └── test ├── java │ └── sample │ └── camel │ └── MySpringBootApplicationTest.java └── resources
As you can see, you have already in place a sample Spring Boot application with a basic Camel Route. Also, we have the Bill of Materials both for Spring Boot and for Camel:
<dependencyManagement> <dependencies> <!-- Spring Boot BOM --> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-dependencies</artifactId> <version>${spring.boot-version}</version> <type>pom</type> <scope>import</scope> </dependency> <!-- Camel BOM --> <dependency> <groupId>org.apache.camel.springboot</groupId> <artifactId>camel-spring-boot-dependencies</artifactId> <version>${camel-version}</version> <type>pom</type> <scope>import</scope> </dependency> </dependencies> </dependencyManagement>
Latest version of Spring Boot and Camel + Spring Boot:
- Spring Boot: 3.2.0
- Camel – Spring Boot: 4.2.0
Check that the following dependencies are in your pom.xml, otherwise integrate your project with them::
<dependencies> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> <exclusions> <exclusion> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-tomcat</artifactId> </exclusion> </exclusions> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-undertow</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-actuator</artifactId> </dependency> <dependency> <groupId>org.apache.camel.springboot</groupId> <artifactId>camel-spring-boot-starter</artifactId> </dependency> <!-- Test --> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-test</artifactId> <scope>test</scope> </dependency> <dependency> <groupId>org.apache.camel</groupId> <artifactId>camel-test-spring-junit5</artifactId> <scope>test</scope> </dependency> </dependencies>
Finally, as our application requires REST Services, we need to add the Camel HTTP dependency to our project:
<dependency> <groupId>org.apache.camel.springboot</groupId> <artifactId>camel-http-starter</artifactId> </dependency>
Failure to add the camel-http-starter dependency, will result in the following Exception if the is not in your Spring Boot Runtime:
java.lang.IllegalStateException: Cannot find RestProducerFactory in Registry or as a Component to use
Coding the Camel + Spring Boot Application
The Camel Route calls a REST Service using a Timer. The Route passes a random id to the REST endpoint to generate a random password:
@Component public class RestRoute extends RouteBuilder { @Override public void configure() throws Exception { restConfiguration().host("localhost").port(8080); from("timer:hello?period={{timer.period}}") .setHeader("id", simple("${random(6,9)}")) .to("rest:get:example/{id}") .log("${body}"); } }
Please note this class contains the @Component annotation to make Camel auto detect this route when starting. The Endpoint is a simple Spring Boot Controller which generates the Random number based on the length id:
@RestController public class MyController { @GetMapping(value = "/example/{id}") public String getRandomString(@PathVariable("id") Integer id) { return "Got " + randomString(id); } String randomString(int len) { String AB = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"; SecureRandom rnd = new SecureRandom(); StringBuilder sb = new StringBuilder(len); for (int i = 0; i < len; i++) sb.append(AB.charAt(rnd.nextInt(AB.length()))); return sb.toString(); } }
Finally, to kick-start the Spring Boot application, we will add a basic Spring Application class with a main method:
@SpringBootApplication public class RestApplication { public static void main(String[] args) { SpringApplication.run(RestApplication.class, args); } }
Running the application
You can run the application just like any Spring Boot application:
mvn clean install spring-boot:run
In conclusion, you will see from the Console, the Timer calls repeatedly the REST Service which produces a Random String:

You can find the source code for this example here: https://github.com/fmarchioni/masterspringboot/tree/master/camel/rest-producer
Another Camel Spring Boot example: a Transformer
Let’s see another example. At first, we will add another Router class named MySpringBootRouter which uses a transformer to log some text messages:
@Component public class MySpringBootRouter extends RouteBuilder { @Override public void configure() { from("timer:hello?period={{timer.period}}") .routeId("hello") .transform() .method("myBean", "saySomething") .filter(simple("${body} contains 'foo'")) .to("log:foo") .end() .to("stream:out"); } }
This Route has a Timer component in it which fires according to the “timer.period” (defined in application.properties). Each time the Timer is fired, the Bean registered under the context “myBean” will be invoked through its method “saySomething”. A Sample filter is included to fetch and log messages whose body contains ‘foo’.
Next, let’s check the Transformation done by the Bean “myBean”:
@Component("myBean") public class MySpringBean { @Value("${greeting}") private String say; public String saySomething() { return say.toUpperCase(); } }
In the method saySomething we have changed the default example to transform the text to uppercase.
The Test class included in the project is in charge to intercept the Camel Route and replace the consumer with a direct consumer.
@SpringBootTest @CamelSpringBootTest public class MySpringBootApplicationTest { @Autowired private CamelContext camelContext; @Autowired private ProducerTemplate producerTemplate; @Test public void test() throws Exception { MockEndpoint mock = camelContext.getEndpoint("mock:stream:out", MockEndpoint.class); AdviceWith.adviceWith(camelContext, "hello", // intercepting an exchange on route r -> { // replacing consumer with direct component r.replaceFromWith("direct:start"); // mocking producer r.mockEndpoints("stream*"); } ); // setting expectations mock.expectedMessageCount(1);mock.expectedBodiesReceived("HELLO WORLD"); // invoking consumer producerTemplate.sendBody("direct:start", null); // asserting mock is satisfied mock.assertIsSatisfied(); } }
Please note we have set to upper case the expected value of the “Hello World” message.
Within the application.properties there are several default message properties. For the scope of this example, the following properties can be adjusted:
# what to say greeting = Hello World # how often to trigger the timer timer.period = 2000
You can run the application with:
mvn install spring-boot:run
You should see that the “HELLO WORLD” message is printed on the Camel spring Boot console:
2021-02-21 18:12:28.138 INFO 6030 --- [ main] com.sample.MySpringBootApplication : Started MySpringBootApplication in 1.991 seconds (JVM running for 2.311) HELLO WORLD HELLO WORLD
Using the REST Controller as Template Producer
Let’s spice a bit our example. As an example, we will add a REST Controller to produce the greeting message:
@RestController public class MyRestController { @Autowired private ProducerTemplate template; @RequestMapping("/hello") public String sayHello(@RequestParam(defaultValue = "frank") String name) { return template.requestBody("direct:sayHello", name).toString(); } }
As you can see, we are using the direct Component which is the abstract way to initialize a Route from a ProducerTemplate object. In a nutshell, the ProducerTemplate will fire the synchronous call to “direct:sayHello” passing as parameter the value for “name” contained in the HTTP request. If no request object has been added, the default value of ‘frank’ will be used.
In order to use this example, we will replace the timer component with “direct:sayHello“:
@Component public class MySpringBootRouter extends RouteBuilder { @Override public void configure() { from("direct:sayHello") .routeId("hello") .transform() .method("myBean", "saySomething") .filter(simple("${body} contains 'foo'")) .to("log:foo") .end() .to("stream:out"); } }
That’s it. Adjust the Test class accordingly. (You can check the full source code below).
You can run the application with:
mvn install spring-boot:run
You can test it as follows:
curl http://localhost:8080/hello?name=Jack
We have just covered two basic examples of Camel applications built using Spring Boot. If you want to read more about Spring Boot applications, check this tutorial: Spring Boot Hello World REST Service
Source code for the second Camel Spring Boot example: https://github.com/fmarchioni/masterspringboot/tree/master/camel/camel-helloworld-spring