Apache Camel

Apache Camel Spring Example

Spring is the inversion of controller framework. Spring’s power comes in the way one can configure a bean and wire the dependencies.

Camel route itself is a mix of various components, spring becomes a natural fit in Camel’s journey. In this article, we will see how spring supports camel using some examples.

Before we start with our example, Let’s look into the setup details.

This example uses the following frameworks:

  1. Maven 3.2.3
  2. Apache Camel 2.15.1
  3. Spring 4.1.5.RELEASE
  4. Eclipse  as the IDE, version Luna 4.4.1.

1. Dependencies

I will be showing you some examples of camel ActiveMQ so you need to add the following dependencies:

  1. camel-core – basic module of apache camel.
  2. camel-stream – We will use this to send output to the console.
  3. camel-jms and activemq-camel – ActiveMQ JMS components.
  4. spring-context and camel-spring – Since we be configuring our camel context in spring.
  5. camel-test-spring – spring testing component
  6. slf4j-api and slf4j-log4j12 – This is for the log component. It relies on slf4j for the logger API and log4j as the logger implementation

pom.xml:

<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
	<modelVersion>4.0.0</modelVersion>
	<groupId>com.javacodegeeks.camel</groupId>
	<artifactId>camelHelloWorld</artifactId>
	<version>0.0.1-SNAPSHOT</version>
	<dependencies>
		<dependency>
			<groupId>org.apache.camel</groupId>
			<artifactId>camel-core</artifactId>
			<version>2.15.1</version>
		</dependency>
		<dependency>
			<groupId>org.apache.camel</groupId>
			<artifactId>camel-stream</artifactId>
			<version>2.15.1</version>
		</dependency>
		<dependency>
			<groupId>org.apache.camel</groupId>
			<artifactId>camel-jms</artifactId>
			<version>2.15.1</version>
		</dependency>
		<dependency>
			<groupId>org.apache.activemq</groupId>
			<artifactId>activemq-camel</artifactId>
			<version>5.6.0</version>
		</dependency>
		<dependency>
			<groupId>org.apache.activemq</groupId>
			<artifactId>activemq-pool</artifactId>
			<version>5.11.1</version>
		</dependency>
		<dependency>
			<groupId>org.springframework</groupId>
			<artifactId>spring-context</artifactId>
			<version>4.1.5.RELEASE</version>
		</dependency>
		<dependency>
			<groupId>org.apache.camel</groupId>
			<artifactId>camel-spring</artifactId>
			<version>2.15.1</version>
		</dependency>
		<dependency>
			<groupId>junit</groupId>
			<artifactId>junit</artifactId>
			<version>4.12</version>
		</dependency>
		<dependency>
			<groupId>org.apache.camel</groupId>
			<artifactId>camel-test-spring</artifactId>
			<version>2.15.2</version>
		</dependency>
		<dependency>
			<groupId>org.slf4j</groupId>
			<artifactId>slf4j-api</artifactId>
			<version>1.7.12</version>
		</dependency>
		<dependency>
			<groupId>org.slf4j</groupId>
			<artifactId>slf4j-log4j12</artifactId>
			<version>1.7.12</version>
		</dependency>
	</dependencies>
</project>

2. Configure a bean in spring

Let’s begin our example by configuring a simple test bean in spring XML context.

TestBean:

package com.javacodegeeks.camel;


public class TestBean {
	public String hello(String msg) {
		return "Hello " + msg;
	}
}

The above bean is configured in spring XML context using element <bean>

applicationContext.xml:

<?xml version="1.0" encoding="UTF-8"?>

<beans xmlns="http://www.springframework.org/schema/beans"
	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	xsi:schemaLocation="
        http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
        http://camel.apache.org/schema/spring http://camel.apache.org/schema/spring/camel-spring.xsd
       ">
    <bean id="testBean" class="com.javacodegeeks.camel.TestBean"/>   
</beans>

We load the spring application context, get the bean from the container and call testBean.hello().

CamelSpringExample:
package com.javacodegeeks.camel;

import org.springframework.context.ConfigurableApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class SpringExample {
	public static final void main(String[] args) throws Exception {
		ConfigurableApplicationContext appContext = new ClassPathXmlApplicationContext(
				"applicationContext.xml");
		try {
			TestBean testBean = (TestBean) appContext.getBean("testBean");
			System.out.println(testBean.hello("Camel and Spring"));
		} finally {
			appContext.close();
		}
	}
}

Output:

Hello Came and Spring:thread(Thread[main,5,main])

This example is kept very simple to brief you about how beans are loaded in spring. In the next section, we will improve the context file to build the camel route.

3. ActiveMQ Example using Java DSL

In this example, we create a route in Java using Java DSL. The messages are read from activemq:queue:start and passed on to the TestBean.hello method which in turn modifies the message and sends it to console.
Our first purpose is to build the CamelContext. In our route, we need access to the TestBean and activeMQ component so first we register the TestBean using jndiContext.bind. We also add the ActiveMQ component to the camel context. Next, we build the route using camelContext.addRoutes. We will see the same example in spring in our next section.

CamelActiveMqExample:

package com.javacodegeeks.camel;

import org.apache.activemq.camel.component.ActiveMQComponent;
import org.apache.camel.CamelContext;
import org.apache.camel.ProducerTemplate;
import org.apache.camel.builder.RouteBuilder;
import org.apache.camel.impl.DefaultCamelContext;
import org.apache.camel.util.jndi.JndiContext;

public class CamelActiveMqExample {
	public static final void main(String[] args) throws Exception {
		JndiContext jndiContext = new JndiContext();
		jndiContext.bind("testBean", new TestBean());
		
		CamelContext camelContext = new DefaultCamelContext(jndiContext);
		camelContext.addComponent("activemq", ActiveMQComponent.activeMQComponent("vm://localhost?broker.persistent=false"));
		try {
			camelContext.addRoutes(new RouteBuilder() {
				public void configure() {
					from("activemq:queue:start")
							.to("bean:testBean?method=hello")
							.to("stream:out");
				}
			});
			ProducerTemplate template = camelContext.createProducerTemplate();
			camelContext.start();
			for (int i = 0; i < 5; i++) {
				template.sendBody("activemq:queue:start", "body" + i);
			}
			Thread.sleep(1000);
		} finally {
			camelContext.stop();
		}
	}
}

Output:

14:21| INFO | BrokerService.java 564 | ActiveMQ JMS Message Broker (localhost, ID:INMAA1-L1005-50028-1433753516461-0:1) started
14:21| ERROR | BrokerService.java 1786 | Temporary Store limit is 50000 mb, whilst the temporary data directory: C:\javacodegeeks_ws\camelSpringExample\activemq-data\localhost\tmp_storage only has 19717 

mb of usable space
14:21| INFO | TransportConnector.java 265 | Connector vm://localhost Started
14:21| INFO | DefaultCamelContext.java 3164 | Route: route1 started and consuming from: Endpoint[activemq://queue:start]
14:21| INFO | DefaultCamelContext.java 2453 | Total 1 routes, of which 1 is started.
14:21| INFO | DefaultCamelContext.java 2454 | Apache Camel 2.15.1 (CamelContext: camel-1) started in 0.691 seconds
Hello body0
Hello body1
Hello body2
Hello body3
Hello body4
14:21| INFO | DefaultCamelContext.java 2660 | Apache Camel 2.15.1 (CamelContext: camel-1) is shutting down

4. Configure Component and Endpoint in Spring

Before we start adding route in spring, you should know that we can also define component and endpoint beans in spring. This allows you to be more explicit, use more meaningful names for the components and endpoints based on the use case at hand.Note that Camel internally uses JmsTemplate to interact with JMS so we also need JmsTemplate bean.
In the below applicationContext.xml, we define

  1. TestBean
  2. JMS ConnectionFactory
  3. ConnectionFactory Pool
  4. JmsTemplate

applicationContext.xml:

<?xml version="1.0" encoding="UTF-8"?>

<beans xmlns="http://www.springframework.org/schema/beans"
	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	xsi:schemaLocation="
        http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
        http://camel.apache.org/schema/spring http://camel.apache.org/schema/spring/camel-spring.xsd
       ">
    <bean id="testBean" class="com.javacodegeeks.camel.TestBean"/>   
	<bean id="jmsConnectionFactory" class="org.apache.activemq.ActiveMQConnectionFactory">
		<property name="brokerURL" value="vm://localhost?broker.persistent=false" />
	</bean>
	<bean id="pooledConnectionFactory" class="org.apache.activemq.pool.PooledConnectionFactory"
		init-method="start" destroy-method="stop">
		<property name="maxConnections" value="8" />
		<property name="connectionFactory" ref="jmsConnectionFactory" />
	</bean>

	<bean id="jmsTemplate" class="org.springframework.jms.core.JmsTemplate">
		<property name="connectionFactory" ref="pooledConnectionFactory" />
	</bean>

</beans>

Now we will configure an endpoint which we will later use it in routing. Its a bean endpoint to invoke a specific method in the bean.

<endpoint id="testBeanUriHelloMethod" uri="bean:testBean?method=hello"/>

We will see in the next section how to build routing in spring and refer to the declared endpoint.

5. ActiveMQ Example using Spring DSL

Camel provides many custom XML extensions that we call in Spring DSL. The Spring DSL allows you to do almost everything you can do in the Java DSL.

You build your route under the <camelContext> element. Each <route> element defines a RouteBuilder. Within the route element, you build the route using elements with names similar to ones used inside the Java DSL RouteBuilder. You start your route with <from> and propagate the message to the <to> endpoint. You can use multiple <to> according to your requirement. In our example below, instead of defining the endpoint using uri we made it to refer to the already registered endpoint using ref attribute.

applicationContext.xml:

<?xml version="1.0" encoding="UTF-8"?>

<beans xmlns="http://www.springframework.org/schema/beans"
	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	xsi:schemaLocation="
        http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
        http://camel.apache.org/schema/spring http://camel.apache.org/schema/spring/camel-spring.xsd
       ">
    <bean id="testBean" class="com.javacodegeeks.camel.TestBean"/>   
	<bean id="jmsConnectionFactory" class="org.apache.activemq.ActiveMQConnectionFactory">
		<property name="brokerURL" value="vm://localhost?broker.persistent=false" />
	</bean>
	<bean id="pooledConnectionFactory" class="org.apache.activemq.pool.PooledConnectionFactory"
		init-method="start" destroy-method="stop">
		<property name="maxConnections" value="8" />
		<property name="connectionFactory" ref="jmsConnectionFactory" />
	</bean>

	<bean id="jmsTemplate" class="org.springframework.jms.core.JmsTemplate">
		<property name="connectionFactory" ref="pooledConnectionFactory" />
	</bean>

	<camelContext xmlns="http://camel.apache.org/schema/spring">

		<route>
			<from uri="activemq:queue:start" />
			<to ref="testBeanUriHelloMethod" />
			<to uri="stream:out" />
		</route>		

	</camelContext>

</beans>

In order to create CamelContext based on the route defined in spring context XML, you need to first load the spring application context and then call:

SpringCamelContext.springCamelContext(appContext, false);

It takes the spring context and returns us the CamelContext. The second parameter is to let the camel know whether you want the CamelContext to be stared automatically.

CamelActivemqExampleUsingSpring:

package com.javacodegeeks.camel;

import org.apache.camel.CamelContext;
import org.apache.camel.ProducerTemplate;
import org.apache.camel.spring.SpringCamelContext;
import org.springframework.context.ConfigurableApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class CamelActivemqExampleUsingSpring {
	public static final void main(String[] args) throws Exception {
		ConfigurableApplicationContext appContext = new ClassPathXmlApplicationContext(
				"applicationContext.xml");
		CamelContext camelContext = SpringCamelContext.springCamelContext(
				appContext, false);
		try {
			camelContext.start();
			ProducerTemplate template = camelContext.createProducerTemplate();
			for (int i = 0; i < 5; i++) {
				template.sendBody("activemq:queue:start", "body" + i);
			}
			Thread.sleep(1000);
		} finally {
			camelContext.stop();
			appContext.close();
		}
	}
}

There is lot of output that shows up in console, pasting most of it here so you know what is going on.

Output:

14:35| INFO | AbstractApplicationContext.java 510 | Refreshing org.springframework.context.support.ClassPathXmlApplicationContext@ed17bee: startup date [Mon Jun 08 14:35:46 IST 

2015]; root of context hierarchy
14:35| INFO | XmlBeanDefinitionReader.java 317 | Loading XML bean definitions from class path resource [applicationContext.xml]
14:35| INFO | BrokerService.java 521 | Using Persistence Adapter: MemoryPersistenceAdapter
14:35| INFO | BrokerService.java 799 | ActiveMQ 5.6.0 JMS Message Broker (localhost) is starting
14:35| INFO | BrokerService.java 801 | For help or more information please see: http://activemq.apache.org/
14:35| INFO | ManagementContext.java 101 | JMX consoles can connect to service:jmx:rmi:///jndi/rmi://localhost:1099/jmxrmi
14:35| INFO | BrokerService.java 564 | ActiveMQ JMS Message Broker (localhost, ID:INMAA1-L1005-51010-1433754347212-0:1) started
14:35| ERROR | BrokerService.java 1786 | Temporary Store limit is 50000 mb, whilst the temporary data directory: C:\javacodegeeks_ws\camelSpringExample\activemq-data\localhost\tmp_storage only has 19715 

mb of usable space
14:35| INFO | TransportConnector.java 265 | Connector vm://localhost Started
14:35| INFO | DefaultCamelContext.java 2418 | Apache Camel 2.15.1 (CamelContext: camel-1) is starting
14:35| INFO | ManagedManagementStrategy.java 187 | JMX is enabled
14:35| INFO | DefaultTypeConverter.java 56 | Loaded 186 type converters
14:35| INFO | DefaultCamelContext.java 2633 | AllowUseOriginalMessage is enabled. If access to the original message is not needed, then its recommended to turn this option off as it may improve 

performance.
14:35| INFO | DefaultCamelContext.java 2643 | StreamCaching is not in use. If using streams then its recommended to enable stream caching. See more details at http://camel.apache.org/stream-caching.html
14:35| INFO | DefaultCamelContext.java 3164 | Route: route1 started and consuming from: Endpoint[activemq://queue:start]
14:35| INFO | DefaultCamelContext.java 2453 | Total 1 routes, of which 1 is started.
14:35| INFO | DefaultCamelContext.java 2454 | Apache Camel 2.15.1 (CamelContext: camel-1) started in 0.233 seconds
14:35| INFO | DefaultCamelContext.java 2418 | Apache Camel 2.15.1 (CamelContext: camel-1) is starting
14:35| INFO | DefaultCamelContext.java 2453 | Total 1 routes, of which 1 is started.
14:35| INFO | DefaultCamelContext.java 2454 | Apache Camel 2.15.1 (CamelContext: camel-1) started in 0.001 seconds
Hello body0
Hello body1
Hello body2
Hello body3
Hello body4
14:35| INFO | DefaultCamelContext.java 2660 | Apache Camel 2.15.1 (CamelContext: camel-1) is shutting down
14:35| INFO | DefaultShutdownStrategy.java 184 | Starting to graceful shutdown 1 routes (timeout 300 seconds)
14:35| INFO | DefaultShutdownStrategy.java 647 | Route: route1 shutdown complete, was consuming from: Endpoint[activemq://queue:start]
14:35| INFO | DefaultShutdownStrategy.java 247 | Graceful shutdown of 1 routes completed in 0 seconds
14:35| INFO | DefaultCamelContext.java 2745 | Apache Camel 2.15.1 (CamelContext: camel-1) uptime 1.083 seconds
14:35| INFO | DefaultCamelContext.java 2746 | Apache Camel 2.15.1 (CamelContext: camel-1) is shutdown in 0.036 seconds
14:35| INFO | AbstractApplicationContext.java 862 | Closing org.springframework.context.support.ClassPathXmlApplicationContext@ed17bee: startup date [Mon Jun 08 14:35:46 IST 2015]; root of context 

hierarchy
14:35| INFO | TransportConnector.java 307 | Connector vm://localhost Stopped
14:35| INFO | BrokerService.java 605 | ActiveMQ Message Broker (localhost, ID:INMAA1-L1005-51010-1433754347212-0:1) is shutting down
14:35| INFO | BrokerService.java 676 | ActiveMQ JMS Message Broker (localhost, ID:INMAA1-L1005-51010-1433754347212-0:1) stopped

6. Define RouteBuilder bean in Spring

In this example, we create route using Java DSL extending RouteBuilder. We will next define the route builder as a bean in spring context XML.

ActiveMqRouteBuilder:

package com.javacodegeeks.camel.routes;

import org.apache.camel.builder.RouteBuilder;

public class ActiveMqRouteBuilder extends RouteBuilder {
	public void configure() {
		from("activemq:queue:start")
                    .to("bean:testBean?method=hello")
                    .to("stream:out");
	}
}

In the below context, we define activeMqRouteBuilder point to ActiveMqRouteBuilde and then refer to the route builder using element <routeBuilder> where attribute ref contains the route builder bean ID.

routeBuilderApplicationContext.xml:

<?xml version="1.0" encoding="UTF-8"?>

<beans xmlns="http://www.springframework.org/schema/beans"
	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	xsi:schemaLocation="
        http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
        http://camel.apache.org/schema/spring http://camel.apache.org/schema/spring/camel-spring.xsd
       ">
    <bean id="testBean" class="com.javacodegeeks.camel.TestBean"/>   
	<bean id="jmsConnectionFactory" class="org.apache.activemq.ActiveMQConnectionFactory">
		<property name="brokerURL" value="vm://localhost?broker.persistent=false" />
	</bean>
	<bean id="pooledConnectionFactory" class="org.apache.activemq.pool.PooledConnectionFactory"
		init-method="start" destroy-method="stop">
		<property name="maxConnections" value="8" />
		<property name="connectionFactory" ref="jmsConnectionFactory" />
	</bean>

	<bean id="jmsTemplate" class="org.springframework.jms.core.JmsTemplate">
		<property name="connectionFactory" ref="pooledConnectionFactory" />
	</bean>

	<bean id="activeMqRouteBuilder" class="com.javacodegeeks.camel.routes.ActiveMqRouteBuilder"/>
	
	<camelContext xmlns="http://camel.apache.org/schema/spring">

		<routeBuilder ref="activeMqRouteBuilder"/>
		
	</camelContext>

</beans>

ActiveMqRouteBuilderExample:

package com.javacodegeeks.camel;

import org.apache.camel.CamelContext;
import org.apache.camel.ProducerTemplate;
import org.apache.camel.spring.SpringCamelContext;
import org.springframework.context.ConfigurableApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class ActiveMqRouteBuilderExample {
	public static final void main(String[] args) throws Exception {
		ConfigurableApplicationContext appContext = new ClassPathXmlApplicationContext(
				"applicationContext.xml");
		CamelContext camelContext = SpringCamelContext.springCamelContext(
				appContext, false);
		try {
			camelContext.start();
			ProducerTemplate template = camelContext.createProducerTemplate();
			for (int i = 0; i < 5; i++) {
				template.sendBody("activemq:queue:start", "body" + i);
			}
			Thread.sleep(1000);
		} finally {
			camelContext.stop();
			appContext.close();
		}
	}
}

Output:

14:48| INFO | DefaultCamelContext.java 2454 | Apache Camel 2.15.1 (CamelContext: camel-1) started in 0.000 seconds
Hello body0
Hello body1
Hello body2
Hello body3
Hello body4
14:48| INFO | DefaultCamelContext.java 2660 | Apache Camel 2.15.1 (CamelContext: camel-1) is shutting down

7. Define Processor in Spring

In this example, we create a custom Processor and then use it in your Spring DSL routing using process element.

MyProcessor:

package com.javacodegeeks.camel;

import java.util.Date;

import org.apache.camel.Exchange;
import org.apache.camel.Processor;

public class MyProcessor implements Processor {

	public void process(Exchange exchange) throws Exception {
		exchange.getIn().setBody("HeartBeat " + new Date());
	}

}

Declare the above created processor as a bean in spring context. Next, we refer the processor in the route. We have created a timer that calls the processor which in turn set the current time to the body.
The final destination is the console where we see the heartbeats.

processorApplicationContext.xml:

<?xml version="1.0" encoding="UTF-8"?>

<beans xmlns="http://www.springframework.org/schema/beans"
	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	xsi:schemaLocation="
        http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
        http://camel.apache.org/schema/spring http://camel.apache.org/schema/spring/camel-spring.xsd
       ">
    <bean id="myProcessor" class="com.javacodegeeks.camel.MyProcessor"/> 
	<camelContext xmlns="http://camel.apache.org/schema/spring">

		<route>
			<from uri="timer:foo?period=1s" />			
			<process ref="myProcessor"/>
			<to uri="stream:out" />
		</route>

	</camelContext>

</beans>

CamelProcessorBeanInSpring:

package com.javacodegeeks.camel;

import org.apache.camel.CamelContext;
import org.apache.camel.spring.SpringCamelContext;
import org.springframework.context.ConfigurableApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class CamelProcessorBeanInSpring {
	public static final void main(String[] args) throws Exception {
		ConfigurableApplicationContext appContext = new ClassPathXmlApplicationContext(
				"processorApplicationContext.xml");
		CamelContext camelContext = SpringCamelContext.springCamelContext(
				appContext, false);
		try {
			camelContext.start();
			Thread.sleep(3000);
		} finally {
			camelContext.stop();
			appContext.close();
		}
	}
}

Output:

15:01| INFO | DefaultCamelContext.java 2454 | Apache Camel 2.15.1 (CamelContext: camel-1) started in 0.000 seconds
HeartBeat Mon Jun 08 15:01:51 IST 2015
HeartBeat Mon Jun 08 15:01:52 IST 2015
HeartBeat Mon Jun 08 15:01:53 IST 2015
15:01| INFO | DefaultCamelContext.java 2660 | Apache Camel 2.15.1 (CamelContext: camel-1) is shutting down

8. Define Multiple Routing in Spring

If you’re using the Spring DSL, can change your routing rules and you don’t have to recompile as it is declarative. In this example, we show how to add multiple routers to the spring context.
You just need to add one more <route> element.

multipleRoutingApplicationContext.xml:

<?xml version="1.0" encoding="UTF-8"?>

<beans xmlns="http://www.springframework.org/schema/beans"
	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	xsi:schemaLocation="
        http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
        http://camel.apache.org/schema/spring http://camel.apache.org/schema/spring/camel-spring.xsd
       ">
    <bean id="testBean" class="com.javacodegeeks.camel.TestBean"/>   
	<bean id="jmsConnectionFactory" class="org.apache.activemq.ActiveMQConnectionFactory">
		<property name="brokerURL" value="vm://localhost?broker.persistent=false" />
	</bean>
	<bean id="pooledConnectionFactory" class="org.apache.activemq.pool.PooledConnectionFactory"
		init-method="start" destroy-method="stop">
		<property name="maxConnections" value="8" />
		<property name="connectionFactory" ref="jmsConnectionFactory" />
	</bean>

	<bean id="jmsTemplate" class="org.springframework.jms.core.JmsTemplate">
		<property name="connectionFactory" ref="pooledConnectionFactory" />
	</bean>

	<camelContext xmlns="http://camel.apache.org/schema/spring">
		<route>
			<from uri="timer:foo?period=1s" />
			<transform>
				<simple>Heartbeat ${date:now:yyyy-MM-dd HH:mm:ss}</simple>
			</transform>
			<to uri="bean:testBean?method=hello" />
			<to uri="activemq:queue:in" />
		</route>

		<route>
			<from uri="activemq:queue:in" />
			<log message="Route message from inbox to outbox queue with data ${body}" />
			<to uri="stream:out" />
		</route>
		
	</camelContext>

</beans>

CamelMultipleRoutingExampleUsingSpring:

package com.javacodegeeks.camel;

import org.apache.camel.CamelContext;
import org.apache.camel.spring.SpringCamelContext;
import org.springframework.context.ConfigurableApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class CamelMultipleRoutingExampleUsingSpring {
	public static final void main(String[] args) throws Exception {
		ConfigurableApplicationContext appContext = new ClassPathXmlApplicationContext(
				"multipleRoutingApplicationContext.xml");
		CamelContext camelContext = SpringCamelContext.springCamelContext(
				appContext, false);
		try {
			camelContext.start();
			Thread.sleep(4000);
		} finally {
			camelContext.stop();
			appContext.close();
		}
	}
}

Output:

14:38| INFO | DefaultCamelContext.java 2454 | Apache Camel 2.15.1 (CamelContext: camel-1) started in 0.000 seconds
14:38| INFO | MarkerIgnoringBase.java 95 | Route message from inbox to outbox queue with data Hello Heartbeat 2015-06-08 14:38:06
Hello Heartbeat 2015-06-08 14:38:06
14:38| INFO | MarkerIgnoringBase.java 95 | Route message from inbox to outbox queue with data Hello Heartbeat 2015-06-08 14:38:07
Hello Heartbeat 2015-06-08 14:38:07
14:38| INFO | MarkerIgnoringBase.java 95 | Route message from inbox to outbox queue with data Hello Heartbeat 2015-06-08 14:38:08
Hello Heartbeat 2015-06-08 14:38:08
14:38| INFO | DefaultCamelContext.java 2660 | Apache Camel 2.15.1 (CamelContext: camel-1) is shutting down

9. Build Routes using Spring Package Scan

You can also use a mix of spring and java to build and start the CamelContext. You can define CamelContext in spring and use Java as the DSL for route development. You can use <packageScan> element to load all the RouteBuilder classes found in the package specified.

Let’s first create a RouteBuilder class in package com.javacodegeeks.camel.routes.

SimpleRoute:

package com.javacodegeeks.camel.routes;

import org.apache.camel.builder.RouteBuilder;

public class SimpleRouteBuilder extends RouteBuilder {
	public void configure() {
		from("timer:foo?period=1s")
		.transform()
		.simple("Heartbeat ${date:now:yyyy-MM-dd HH:mm:ss}")
		.to("stream:out");
	}
}

In the below context, we add a <packageScan> element for package com.javacodegeeks.camel.routes. If you don’t want all the route builders to be loaded, you can exclude them in <excludes> attribute.

springPackageScanApplicationContext.xml:

<?xml version="1.0" encoding="UTF-8"?>

<beans xmlns="http://www.springframework.org/schema/beans"
	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	xsi:schemaLocation="
        http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
        http://camel.apache.org/schema/spring http://camel.apache.org/schema/spring/camel-spring.xsd
       ">
	<camelContext xmlns="http://camel.apache.org/schema/spring">

		<packageScan>
			<package>com.javacodegeeks.camel.routes</package>
			<excludes>*ActiveMq*</excludes>
		</packageScan>

	</camelContext>

</beans>

Output:

Heartbeat 2015-06-08 15:23:54
Heartbeat 2015-06-08 15:23:55
Heartbeat 2015-06-08 15:23:56
Heartbeat 2015-06-08 15:23:57

10. Route Building using Spring Component Scan

Just like the package scan you can also find routes using component scan. Declare a <contextScan> element so that spring can use its component-scan feature to load any Camel route builders that are marked with the @org.springframework.stereotype.Component annotation. Just like package scan, you can specify the package name in base-package attribute.

SimpleRouteBuilder:

package com.javacodegeeks.camel.routes;

import org.apache.camel.builder.RouteBuilder;
import org.springframework.stereotype.Component;

@Component
public class SimpleRouteBuilder extends RouteBuilder {
	public void configure() {
		from("timer:foo?period=1s")
		.transform()
		.simple("Heartbeat ${date:now:yyyy-MM-dd HH:mm:ss}")
		.to("stream:out");
	}
}

springComponentScanApplicationContext.xml:

<?xml version="1.0" encoding="UTF-8"?>

<beans xmlns="http://www.springframework.org/schema/beans"
	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	xmlns:context="http://www.springframework.org/schema/context"
	xsi:schemaLocation="
        http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
        http://camel.apache.org/schema/spring http://camel.apache.org/schema/spring/camel-spring.xsd
        http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd
       ">
    <context:component-scan base-package="com.javacodegeeks.camel.routes"/>   
	<camelContext xmlns="http://camel.apache.org/schema/spring">
		<contextScan/>
	</camelContext>

</beans>

SpringComponentScanExample:

package com.javacodegeeks.camel;

import org.apache.camel.CamelContext;
import org.apache.camel.spring.SpringCamelContext;
import org.springframework.context.ConfigurableApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class SpringComponentScanExample {
	public static final void main(String[] args) throws Exception {
		ConfigurableApplicationContext appContext = new ClassPathXmlApplicationContext(
				"springComponentScanApplicationContext.xml");
		CamelContext camelContext = SpringCamelContext.springCamelContext(
				appContext, false);
		try {
			camelContext.start();
			Thread.sleep(4000);
		} finally {
			camelContext.stop();
			appContext.close();
		}
	}
}

Output:

15:35| INFO | DefaultCamelContext.java 2454 | Apache Camel 2.15.1 (CamelContext: camel-1) started in 0.000 seconds
Heartbeat 2015-06-08 15:35:52
Heartbeat 2015-06-08 15:35:53
Heartbeat 2015-06-08 15:35:54
Heartbeat 2015-06-08 15:35:55
15:35| INFO | DefaultCamelContext.java 2660 | Apache Camel 2.15.1 (CamelContext: camel-1) is shutting down

11. Import Route in Spring

You may want to separate out your routes into several XML files and then import them into the main context XML containing the <camelContext>. When you do that you can refer to the route context you want to build.
In the below XML, we define the routes within a <routeContext> element. We also assign an id so that we can refer to it later in main XML.

route.xml:

<?xml version="1.0" encoding="UTF-8"?>

<beans xmlns="http://www.springframework.org/schema/beans"
	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	xsi:schemaLocation="
        http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
        http://camel.apache.org/schema/spring http://camel.apache.org/schema/spring/camel-spring.xsd
       ">
	<routeContext id="heartbeatRoute"
		xmlns="http://camel.apache.org/schema/spring">
		<route>
			<from uri="timer:foo?period=1s" />
			<transform>
				<simple>Heartbeat ${date:now:yyyy-MM-dd HH:mm:ss}</simple>
			</transform>
			<to uri="stream:out" />
		</route>
	</routeContext>
</beans>

We refer to the route defined in the <routeContextRef> element.

importRouteApplicationContext.xml:

<?xml version="1.0" encoding="UTF-8"?>

<beans xmlns="http://www.springframework.org/schema/beans"
	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	xsi:schemaLocation="
        http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
        http://camel.apache.org/schema/spring http://camel.apache.org/schema/spring/camel-spring.xsd
       ">
	<import resource="route.xml" />
	<camelContext xmlns="http://camel.apache.org/schema/spring">
		<routeContextRef ref="heartbeatRoute" />
	</camelContext>
</beans>

SpringImportRouteExample:

package com.javacodegeeks.camel;

import org.apache.camel.CamelContext;
import org.apache.camel.spring.SpringCamelContext;
import org.springframework.context.ConfigurableApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class SpringImportRouteExample {
	public static final void main(String[] args) throws Exception {
		ConfigurableApplicationContext appContext = new ClassPathXmlApplicationContext(
				"importRouteApplicationContext.xml");
		CamelContext camelContext = SpringCamelContext.springCamelContext(
				appContext, false);
		try {
			camelContext.start();
			Thread.sleep(3000);
		} finally {
			camelContext.stop();
			appContext.close();
		}
	}
}

Output:

15:54| INFO | DefaultCamelContext.java 2454 | Apache Camel 2.15.1 (CamelContext: camel-1) started in 0.000 seconds
Heartbeat 2015-06-08 15:54:14
Heartbeat 2015-06-08 15:54:15
Heartbeat 2015-06-08 15:54:16
15:54| INFO | DefaultCamelContext.java 2660 | Apache Camel 2.15.1 (CamelContext: camel-1) is shutting down

12. Testing Camel using Spring

The Spring Framework also makes it easy to test. In the below example we create a test suite which runs with spring provided SpringJUnit4ClassRunner. You need to specify it in @RunWith attribute.

SpringCamelTest-context.xml:

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:camel="http://camel.apache.org/schema/spring"
       xsi:schemaLocation="
       http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
       http://camel.apache.org/schema/spring http://camel.apache.org/schema/spring/camel-spring.xsd
    ">

    <camelContext xmlns="http://camel.apache.org/schema/spring">
        <!-- define a producer template -->
        <template id="producer"/>
        <!-- define a consumer template -->
        <consumerTemplate id="consumer"/>
        
        <route>
            <from uri="seda:foo"/>
            <to id="result" uri="mock:result"/>
        </route>
    </camelContext>
   
</beans>

We can use Spring for dependency injection and Camel Mock and Test endpoints to verify and assert. Annotation @ContextConfiguration will automatically load the spring context XML

SpringCamelTest-context.xml. If you want to autowire the beans you need to use @Autowired annotation. If you want to inject an endpoint use @EndpointInject.
In the below test case, we send some sample text to seda:foo and then we expect it to be delivered to the mock:result endpoint.In the other segment, send some message to seda:start and then the consumer consumes the body from seda:start.

SpringCamelTest:

package com.javacodegeeks.camel;

import junit.framework.TestCase;

import org.apache.camel.ConsumerTemplate;
import org.apache.camel.EndpointInject;
import org.apache.camel.ProducerTemplate;
import org.apache.camel.component.mock.MockEndpoint;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration
public class SpringCamelTest extends TestCase {

    @Autowired
    private ProducerTemplate producer;

    @Autowired
    private ConsumerTemplate consumer;

    @EndpointInject(ref = "result")
    private MockEndpoint mock;

    @Test
    public void testConsumeTemplate() throws Exception {
        // we expect Hello World received in our mock endpoint
        mock.expectedBodiesReceived("Hello World");

        // we use the producer template to send a message to the seda:start endpoint
        producer.sendBody("seda:start", "Hello World");

        // we consume the body from seda:start
        String body = consumer.receiveBody("seda:start", String.class);
        assertEquals("Hello World", body);

        // and then we send the body again to seda:foo so it will be routed to the mock
        // endpoint so our unit test can complete
        producer.sendBody("seda:foo", body);

        // assert mock received the body
        mock.assertIsSatisfied();
    }

}

13. Download the Eclipse Project

In this article, I showed you Apache Camel Spring Example.

Download
You can download the full source code of this example here: camelSpringExample.zip

Ram Mokkapaty

Ram holds a master's degree in Machine Design from IT B.H.U. His expertise lies in test driven development and re-factoring. He is passionate about open source technologies and actively blogs on various java and open-source technologies like spring. He works as a principal Engineer in the logistics domain.
Subscribe
Notify of
guest

This site uses Akismet to reduce spam. Learn how your comment data is processed.

0 Comments
Inline Feedbacks
View all comments
Back to top button