Monday, June 15, 2015

Spring JMS with ActiveMQ – hello world example – receive message using annotation

Since spring 4.1, using spring jms  to receive message can even easier than before. Just add one annotation @JmsListener before any POJO’s method. In this article, a hello world example will show how easy it can be done.

There are other ways to  receive message from ActiveMQ broker using Spring JMS, examples are provided here

The example on how to send out message with Spring JMS and ActiveMQ is in this article.

0. What you need

  • JDK 1.7+
  • Maven 3.2.1
  • ActiveMQ 5.10.0
  • Spring 4.1.0.RELEASE

In this example  we'll run the ActiveMQ broker on a machine of IP 192.168.203.143 with default port 61616.

1. Configure maven 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>org.springframework.samples</groupId>
<artifactId>spring-jms-activemq-receive-annotation</artifactId>
<version>0.0.1-SNAPSHOT</version>

<properties>
<!-- Spring version -->
<spring-framework.version>4.1.0.RELEASE</spring-framework.version>
<!-- ActiveMQ version -->
<activemq.version>5.10.0</activemq.version>
</properties>

<dependencies>
<!-- Spring Artifacts -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-jms</artifactId>
<version>${spring-framework.version}</version>
</dependency>

<!-- ActiveMQ Artifact -->
<dependency>
<groupId>org.apache.activemq</groupId>
<artifactId>activemq-spring</artifactId>
<version>${activemq.version}</version>
</dependency>
</dependencies>

<!-- Use Jave 1.7 -->
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>2.5.1</version>
<configuration>
<source>1.7</source>
<target>1.7</target>
</configuration>
</plugin>
</plugins>
</build>
</project>

There are 2 dependencies, spring-jms and activemq-spring. JDK version is specified to 1.7


2. Define Java class


There are 2 classes in this demo. The first one is a simple spring bean.

package com.shengwang.demo;

import org.springframework.jms.annotation.JmsListener;
import org.springframework.messaging.handler.annotation.SendTo;
import org.springframework.stereotype.Service;

@Service
public class JmsMessageListener {

@JmsListener(destination="SendToRecv")
@SendTo("RecvToSend")
public String processMessage(String text) {
System.out.println("Received: " + text);
return "ACK from handleMessage";
}
}

The only thing make this class different from a common spring bean is the @JmsListener and @SendTo annotations before the method. The @JmsListener tell spring context the following method will be used whenever a message is coming from the destination "SendToRecv" asynchronously. The @SendTo annotation specify the destination for return message from the method.


The second class is the main class.

package com.shengwang.demo;

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

public class DemoMain {
public static void main(String[] args) {
ApplicationContext ctx = new ClassPathXmlApplicationContext("app-context.xml");
}
}

There's only one line in the main to create the spring context. Imagine what will happen when running it. Will the main exit immediately after the line? No, Because the control is in Spring context, which is waiting for incoming messages from JMS. That's the feeling of Inversion of Control (IoC).  Let the context choose what to do.


3. Spring configuration


In the Spring configuration app-context.xml, there are 3 beans need to define:


  • ActiveMQ connection factory
  • Spring connection factory (use the above one)
  • Spring jms listener container factory (use the above one)
<?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:beans="http://www.springframework.org/schema/beans"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:jms="http://www.springframework.org/schema/jms"
xsi:schemaLocation="http://www.springframework.org/schema/jms
http://www.springframework.org/schema/jms/spring-jms-4.1.xsd
http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context.xsd">


<context:component-scan base-package="com.shengwang.demo" />

<!-- enable the configuration of jms on annotations -->
<jms:annotation-driven/>

<!-- =============================================== -->
<!-- JMS Common, define JMS connectionFactory -->
<!-- =============================================== -->
<!-- Activemq connection factory -->
<bean id="amqConnectionFactory" class="org.apache.activemq.ActiveMQConnectionFactory">
<!-- brokerURL -->
<constructor-arg index="0" value="tcp://192.168.202.168:61616" />
</bean>

<!-- Pooled Spring connection factory -->
<bean id="connectionFactory"
class="org.springframework.jms.connection.CachingConnectionFactory">
<constructor-arg ref="amqConnectionFactory" />
</bean>

<!-- =============================================== -->
<!-- JMS receive, define JmsListenerContainerFactory -->
<!-- =============================================== -->
<bean id="jmsListenerContainerFactory"
class="org.springframework.jms.config.DefaultJmsListenerContainerFactory">
<property name="connectionFactory" ref="connectionFactory" />
<property name="concurrency" value="3-10"/>
</bean>

</beans>

There's a concurrency parameter for the bean jmsListenerContainerFactory, which is 3-10 here. It means at lease 3 beans instances are waiting for the incoming message. It can process 10 incoming messages in parallel.


Everything is almost done now. Let's review the directory structure for our maven project.


image


4. Run the code


Before you can run the code, you need to make sure the ActiveMQ broker is running. So our jave code can connect to it and receive message from it.   Make sure the broker IP and port are correct in your spring configuration file "app-context.xml". Run the ActiveMQ broker like with this command.

ACTIVEMQ_INSTALL_DIR/bin/activemq start

Now you can run you main class. you can run it from IDE such as eclipse, or you can run it direct in command line by using maven.

cd spring-jms-activemq-receive-annotation
# run mvn from project directory
mvn exec:java -Dexec.mainClass="com.shengwang.demo.DemoMain"

After running the demo, Let's check from ActiveMQ Web Console. (http://activemqIp:8161)


image


Now send a message to the Queue "SendToRecv", and refresh the browser.


image


Check the reply message. The return of the listener method will be send back as JMS message automatically.


image

2 comments:

Powered by Blogger.

About The Author

My Photo
Has been a senior software developer, project manager for 10+ years. Dedicate himself to Alcatel-Lucent and China Telecom for delivering software solutions.

Pages

Unordered List