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:
- Maven 3.2.3
- Apache Camel 2.15.1
- Spring 4.1.5.RELEASE
- 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:
camel-core
– basic module of apache camel.camel-stream
– We will use this to send output to the console.camel-jms
andactivemq-camel
– ActiveMQ JMS components.spring-context
andcamel-spring
– Since we be configuring our camel context in spring.camel-test-spring
– spring testing componentslf4j-api
andslf4j-log4j12
– This is for the log component. It relies onslf4j
for the logger API andlog4j
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
- TestBean
- JMS ConnectionFactory
- ConnectionFactory Pool
- 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.
You can download the full source code of this example here: camelSpringExample.zip