Spring Boot Example of Spring Integration and ActiveMQ

Spring Boot Example of Spring Integration and ActiveMQ

In this post, I’m going to walk you through using Spring Boot to setup a Hello World example using Spring Integration and ActiveMQ. We’ll configure Spring Integration to listen on a ActiveMQ queue. For fun, I’ll use Spock to place a message on the queue, and we can watch Spring Integration receive the JMS Message and print a message to the console.

Spring Boot Project Setup

Spring Initializr

Using IntelliJ to create a new project, I’ll select the option to use the Spring Initializr to create my new Spring Boot project. The IntellIj dialog makes it easy to create a Spring Boot project.

In this case, I’m selecting the latest version of Spring Boot (1.3.0.M3) at the time of writing, and the option for Spring Integration.

After completing the steps in IntelliJ, I’ll have a fresh Maven project to work with for this example.

Spring Integration and ActiveMQ Dependencies

Spring Boot does a pretty good job of bringing in the basic dependencies. Using the Maven support in IntelliJ, we can look at Maven dependencies for our project. You can see that via the Spring Boot artifacts, we’re bringing in the basic dependencies for Spring Integration.

At the time of writing, the Spring Initializr does not support ActiveMQ directly. I didn’t look to see if the Spring Boot team defined a Maven artifact for this or not. But, it’s simple enough to add the dependencies we will need for Spring Integration and ActiveMQ.

Notice how I have not added version information to the dependencies? That gets inherited from the parent Spring Boot Maven POM.

1

2

3

4

5

6

7

8

9

10

11

12

13

<!--JMS support-->

<dependency>

<groupId>org.springframework</groupId>

<artifactId>spring-jms</artifactId>

</dependency>

<dependency>

<groupId>org.springframework.integration</groupId>

<artifactId>spring-integration-jms</artifactId>

</dependency>

<dependency>

<groupId>org.apache.activemq</groupId>

<artifactId>activemq-broker</artifactId>

</dependency>

ActiveMQ Spring Boot Configuration

Like many other things, Spring Boot makes our task of configuring ActiveMQ easier. For the purposes of our example, we want to use an embedded ActiveMQ broker. This is common to use when developing Spring projects which use ActiveMQ. Often when developing enterprise applications using Spring, you will use a ActiveMQ embedded broker for development and then have a configuration to use IBM’s MQSeries in production.

ActiveMQ Broker

By just having ActiveMQ on our build path, Spring Boot will automatically set up a ActiveMQ broker. We need to set a couple properties to make it an in memory broker, without connection pooling. We can do this by setting two properties for Spring Boot.

application.properties

1

2

spring.activemq.in-memory=true

spring.activemq.pooled=false

ActiveMQ Queue Configuration

We also need to setup a queue for our example. We can do this in a Spring Java Configuration class as follows.

ActiveMQConfig.java

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

packageguru.springframework.configuration;

import org.apache.activemq.command.ActiveMQQueue;

import org.springframework.context.annotation.Bean;

import org.springframework.context.annotation.Configuration;

import javax.jms.Queue;

@Configuration

publicclassActiveMQConfig{

publicstaticfinalStringHELLO_QUEUE="hello.queue";

@Bean

publicQueue helloJMSQueue(){

returnnewActiveMQQueue(HELLO_QUEUE);

}

}

This is all we need to do to configure ActiveMQ for our example. Spring Boot will take care of the rest.

Spring Integration Configuration

Spring Integration JMS Channel Adapter

Spring Integration comes with a number of different channel adapters. In this case, we need to configure a JMS channel adapter. This will serve as a transparent bridge between Spring Integration Messaging and JMS Messaging.

In the Spring Integration XML configuration below, I’ve defined a Spring Integration JMS channel adapter. The destination property is set to the name of the ActiveMQ queue bean we defined above. (When using Spring Java configuration, the bean reference becomes is inherited from the method name in the configuration class.) I’ve also added a Spring Integration channel to the configuration.

This acts as a bridge, messages coming from the JMS queue will get sent the the Spring Integration channel, and messages sent to the Spring Integration channel will get passed along to the JMS queue.

Spring Boot Configuration

We need to tell Spring Boot about the Spring Integration XML configuration file. We can to this by adding an
ImportResource annotation to the Spring Boot application class file as follows.

HelloWorldSiActivemqApplication.class

1

2

3

4

5

6

7

8

9

10

11

12

13

14

packageguru.springframework;

import org.springframework.boot.SpringApplication;

import org.springframework.boot.autoconfigure.SpringBootApplication;

import org.springframework.context.annotation.ImportResource;

@SpringBootApplication

@ImportResource("classpath*:/spring/si-config.xml")

publicclassHelloWorldSiActivemqApplication{

publicstaticvoidmain(String[]args){

SpringApplication.run(HelloWorldSiActivemqApplication.class,args);

}

}

Spock Configuration

Maven Dependencies

To enable Spock support add the following dependencies to your Maven pom file.

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

<!--needed tosupport Spock-->

<dependency>

<groupId>org.codehaus.groovy</groupId>

<artifactId>groovy-all</artifactId>

<version>2.4.3</version>

</dependency>

<dependency>

<groupId>org.spockframework</groupId>

<artifactId>spock-core</artifactId>

<version>1.0-groovy-2.4</version>

</dependency>

<dependency>

<groupId>org.spockframework</groupId>

<artifactId>spock-spring</artifactId>

<version>1.0-groovy-2.4</version>

</dependency>

Maven Compiler Plugin

Spock test classes are written in Groovy. You will need to add a Groovy compiler to your Maven build. I like to use the Groovy Eclipse Compiler. Add the following plugin to your build plugins.

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

<plugin>

<artifactId>maven-compiler-plugin</artifactId>

<!--2.8.0-01andlater require maven-compiler-plugin3.1orhigher-->

<version>3.1</version>

<configuration>

<compilerId>groovy-eclipse-compiler</compilerId>

</configuration>

<dependencies>

<dependency>

<groupId>org.codehaus.groovy</groupId>

<artifactId>groovy-eclipse-compiler</artifactId>

<version>2.9.2-01</version>

</dependency>

<!--for2.8.0-01andlater you must have an explicit dependency on groovy-eclipse-batch-->

<dependency>

<groupId>org.codehaus.groovy</groupId>

<artifactId>groovy-eclipse-batch</artifactId>

<version>2.4.3-01</version>

</dependency>

</dependencies>

</plugin>

Sending a JMS Message Using Spock

There’s a lot of different ways to send a JMS message. I chose to use Spock for this example mostly for fun. I enjoy using Spock. In this example, I’ve setup Spock to use the same Spring context used by the Spring Boot Application. The Spring Boot Application class is actually a Spring Configuration class you can source into your Spring Integration tests.

Spock Spring Integration Test

In this Spock Integration test, using the Spring Boot configuration, I autowire in an instance of the JMS connection factory and setup a JMS producer to send a text message. This will drop a text message on the the same ActiveMQ JMS queue we configured Spring Integration to listen on.

at org.springframework.beans.factory.support.BeanDefinitionValueResolver.resolveReference(BeanDefinitionValueResolver.java:359)

at org.springframework.beans.factory.support.BeanDefinitionValueResolver.resolveValueIfNecessary(BeanDefinitionValueResolver.java:108)

at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.applyPropertyValues(AbstractAutowireCapableBeanFactory.java:1481)

at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.populateBean(AbstractAutowireCapableBeanFactory.java:1226)

at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:543)

at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:482)

at org.springframework.beans.factory.support.AbstractBeanFactory$1.getObject(AbstractBeanFactory.java:305)

at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:230)

at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:301)

at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:196)

at org.springframework.beans.factory.support.DefaultListableBeanFactory.preInstantiateSingletons(DefaultListableBeanFactory.java:772)

at org.springframework.context.support.AbstractApplicationContext.finishBeanFactoryInitialization(AbstractApplicationContext.java:834)

at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:537)

at org.springframework.boot.SpringApplication.refresh(SpringApplication.java:667)

at org.springframework.boot.SpringApplication.doRun(SpringApplication.java:342)

at org.springframework.boot.SpringApplication.run(SpringApplication.java:273)

at org.springframework.boot.test.SpringApplicationContextLoader.loadContext(SpringApplicationContextLoader.java:102)

at org.springframework.test.context.cache.DefaultCacheAwareContextLoaderDelegate.loadContextInternal(DefaultCacheAwareContextLoaderDelegate.java:98)

at org.springframework.test.context.cache.DefaultCacheAwareContextLoaderDelegate.loadContext(DefaultCacheAwareContextLoaderDelegate.java:116)

... 13 more

Caused by: org.springframework.beans.factory.NoSuchBeanDefinitionException: No bean named 'connectionFactory' is defined

at org.springframework.beans.factory.support.DefaultListableBeanFactory.getBeanDefinition(DefaultListableBeanFactory.java:698)

at org.springframework.beans.factory.support.AbstractBeanFactory.getMergedLocalBeanDefinition(AbstractBeanFactory.java:1174)

at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:283)

at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:196)

at org.springframework.beans.factory.support.BeanDefinitionValueResolver.resolveReference(BeanDefinitionValueResolver.java:351)

... 31 more

Spring Integration JMS Configuration for Spring Boot

Intentionally left an error in the Spring Integration configuration to demonstrate this error. The Spring Integration configuration be default is looking for a Spring Bean called ‘connectionFactory’. Spring Boot by default, creates the JMS connection factory using the name ‘jmsConnectionFactory’.

The solution is easy enough to implement. We just need to update the Spring Integration channel adapter to use the Spring Bean ‘jmsConnectionFactory’ instead of it’s default value of ‘connectionFactory.

Conclusion

In this Spring Framework example, I’ve shown you how easy it is to use Spring Boot to configure an Active MQ broker for use with Spring Integration. This blog post was inspired by a real world example where I was coding a enterprise service using the Spring Framework. I needed to use Spring Integration to consume messages off of a MQSeries JMS queue. MQSeries is great, but its not very light weight, nor is it appropriate for Integration tests. Thus, I wrote my integration tests to use an embedded ActiveMQ broker. You can see how easy it was to use Spring Boot to provide the ActiveMQ broker, and dependency injection to wire everything up.

jt

I find it strange that you use Spring XML – in 2016. And with Spring Boot – which specifically recommends annotation-based config. Those XML files are at least 4 years since you should have deleted out of your brain. I loathe XML so intensely – in particular when it comes to IoC/DI and the extreme hassle you get from refactoring – that I went from Spring to Guice due to “Crazy Bob’s” amazing @Inject annotations the minute Guice was released. Then, when Spring wholeheartedly copied Guice some years later, I went back.