ActiveMQ Producer – Consumer Example – Spring Boot

Messaging is a way of communicating between entities. A sender sends a message to a messaging system, and also there can be one or multiple consumers listening to the queue to receive the messages. Messaging also makes the system loosely coupled as the sender and receiver are not communicating with each other directly. Also, the spring boot framework provides the required support to easily implement ActiveMQ producer-consumer application.

In this article, we will learn how to use the Apache ActiveMQ with Spring Boot for implementing the JMS(Java Messaging System) producer-consumer application.

Technologies used in this article are:

  • Spring Boot version : 2.3.0.RELEASE
  • Java version 1.8
  • Apache ActiveMQ 5.15.13

Table of Contents

Setting up the ActiveMQ

We can download the latest version of the ActiveMQ installer from here.

On a Windows machine, we can start the server by running the .bat file from the extracted zip file. Navigate to the apache-activemq-x.xx.xx\bin\winxx directory and start the server by running the .bat file.

After starting the ActiveMQ server locally, we can access the Web console at http://localhost:8161.

The default username is admin, and the password is admin.

Once we log in successfully, we get the below screen.

ActiveMQ on windows

Click on the Manage ActiveMQ broker link to open the ActiveMQ console window, as shown below.

Here, we can view the topics, queues, etc. We can also notice that currently, there are no messages in the queue.

ActiveMQ empty queue

Creating the producer application

Let us create a Spring Boot application that produces the message to the ActiveMQ message queue.

Create the application with required dependencies

Create a Spring Boot application with spring-boot-starter-activemq, spring-boot-starter-web, and lombok dependencies.

The Spring Boot ActiveMQ starter dependency also provides us the required auto-configuration along with an embedded in memory ActiveMQ server.

The dependencies we added to the pom.xml file are given below.

<dependency>
	<groupId>org.springframework.boot</groupId>
	<artifactId>spring-boot-starter-activemq</artifactId>
</dependency>
<dependency>
	<groupId>org.springframework.boot</groupId>
	<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
	<groupId>org.projectlombok</groupId>
	<artifactId>lombok</artifactId>
	<optional>true</optional>
</dependency>

Create a DTO class

Create a java DTO class with the name Student. We will use the student object as message content and also send that to the ActiveMQ message queue.

package com.asbnotebook.dto;
import lombok.Getter;
import lombok.Setter;
import lombok.ToString;
@Getter
@Setter
@ToString
public class Student {
	
	private Integer id;
	private String name;
}

Add required configuration

Create a spring configuration class with the name StudentConfiguration.

package com.asbnotebook.config;
import javax.jms.ConnectionFactory;
import org.springframework.boot.autoconfigure.jms.DefaultJmsListenerContainerFactoryConfigurer;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.jms.config.DefaultJmsListenerContainerFactory;
import org.springframework.jms.config.JmsListenerContainerFactory;
import org.springframework.jms.support.converter.MappingJackson2MessageConverter;
import org.springframework.jms.support.converter.MessageConverter;
import org.springframework.jms.support.converter.MessageType;
@Configuration
public class StudentConfig {
	@Bean // Serialize message content to json using TextMessage
	public MessageConverter jacksonJmsMessageConverter() {
		MappingJackson2MessageConverter converter = new MappingJackson2MessageConverter();
		converter.setTargetType(MessageType.TEXT);
		converter.setTypeIdPropertyName("_asb_");
		return converter;
	}
}
  • @Configuration: This annotation marks the class as a configuration class and adds it to the Spring application context.
  • MessageConverter: We are using the MappingJackson2MessageConverter, and the target type is of Text format. The DTO object sent to the message queue in the JSON text format.
  • TypeId: An id that should match both on the consumer and producer side. We can also set any value as TypeID.

Producing the message

Create a java class with the name StudentProducer.

Spring framework also provides a JmsTemplate that we can use to publish the message to the ActiveMQ message queue.

The convertAndSend() method serializes the object and sends it to the message queue.

package com.asbnotebook.jms;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.jms.core.JmsTemplate;
import org.springframework.stereotype.Component;
import com.asbnotebook.dto.Student;
import lombok.extern.slf4j.Slf4j;
@Component
@Slf4j
public class StudentProducer {
	@Autowired
	private JmsTemplate jmsTemplate;
	public void sendTo(String destination, Student student) {
		jmsTemplate.convertAndSend(destination, student);
		log.info("Producer> Message Sent");
	}
}

Also, create a RESTful POST endpoint to send the Student object to the message queue.

This endpoint allows us to post the Student object to the message queue.

@SpringBootApplication
public class SpringBootActivemqProducerExampleApplication {
	@Autowired
	StudentProducer studentProducer;
	@Value("${activemq.destination}")
	private String destination;
	public static void main(String[] args) {
		SpringApplication.run(SpringBootActivemqProducerExampleApplication.class, args);
	}
	@RestController
	public class StudentController {
		@PostMapping("/")
		public String sendMessage(@RequestBody Student student) {
			studentProducer.sendTo(destination, student);
			return "success";
		}
	}
}

Producer ActiveMQ configuration properties

Add the below configuration properties to the Spring Boot applications application.properties file.

spring.activemq.in-memory=false
spring.activemq.broker-url=tcp://localhost:61616
spring.activemq.user=admin
spring.activemq.password=admin
activemq.destination=student
  • spring.activemq.in-memory: Value is set to false, as we are using external ActiveMQ server.
  • spring.activemq.broker-url: ActiveMQ broker URL.
  • Also, set the Username and password if any is using the spring.activemq.user and spring.activemq.password configuration properties.
  • activemq.destination: A queue/topic name to which the data is published.

Creating the consumer application

Create a consumer application with the required dependencies.

Use the same dependencies that we have used during the creation of the JMS producer application.

Copy the Student.java DTO class from the JMS publisher application.

Create a configuration class

Create a configuration class with the name StudentConfig.java

package com.asbnotebook.config;
import javax.jms.ConnectionFactory;
import org.springframework.boot.autoconfigure.jms.DefaultJmsListenerContainerFactoryConfigurer;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.jms.config.DefaultJmsListenerContainerFactory;
import org.springframework.jms.config.JmsListenerContainerFactory;
import org.springframework.jms.support.converter.MappingJackson2MessageConverter;
import org.springframework.jms.support.converter.MessageConverter;
import org.springframework.jms.support.converter.MessageType;
@Configuration
public class StudentConfig {
	@Bean
	public JmsListenerContainerFactory<?> jmsFactory(ConnectionFactory connectionFactory,
			DefaultJmsListenerContainerFactoryConfigurer configurer) {
		DefaultJmsListenerContainerFactory factory = new DefaultJmsListenerContainerFactory();
		factory.setMessageConverter(jacksonJmsMessageConverter());
		configurer.configure(factory, connectionFactory);
		return factory;
	}
	@Bean // Serialize message content to json using TextMessage
	public MessageConverter jacksonJmsMessageConverter() {
		MappingJackson2MessageConverter converter = new MappingJackson2MessageConverter();
		converter.setTargetType(MessageType.TEXT);
		converter.setTypeIdPropertyName("_asb_");
		return converter;
	}
}
  • We have created a JmsContainerFactory bean and also set the message converter to our custom jacksonJmsConverter(). Even though this is not required, we can use this factory bean to customize the Jms listener(Like setting the error handling, etc.)
  • The Message converter is a similar bean that we have created for producer application.

Creating the consumer

package com.asbnotebook.jms;
import org.springframework.jms.annotation.JmsListener;
import org.springframework.stereotype.Component;
import com.asbnotebook.dto.Student;
import lombok.extern.slf4j.Slf4j;
@Component
@Slf4j
public class StudentConsumer {
	@JmsListener(destination = "${activemq.destination}", containerFactory = "jmsFactory")
	public void processToDo(Student student) {
		log.info("Consumer> " + student);
	}
}
  • @JmsListener: The method annotated with this annotation is a JMS listener method. The listener listens to the specified message queue/topic.
  • destination: Name of the JMS topic/queue.
  • containerFactory: This property specifies the custom container factory we have created earlier in the configuration class.

Consumer ActiveMQ configuration properties

These are the configuration properties that are similar to that of producer application configuration.

Update the server port number so that we can simultaneously start both producer and consumer applications.

spring.activemq.in-memory=false
spring.activemq.broker-url=tcp://localhost:61616
spring.activemq.user=admin
spring.activemq.password=admin
activemq.destination=student
server.port=8001

Testing the application

Both producer and consumer applications are ready now. With the ActiveMQ server running, let’s start testing the application.

Producer application

Start the producer Spring boot application. This application will run on default server port 8080.

As, we have a POST method, that allows us to pass the Student object as shown below.

Spring boot activeMq

Also, the ActiveMQ server console displays the published messages in the queue.

Spring Boot ActiveMQ example

We can observe the message that is enqueued on the ActiveMQ server.

ActiveMQ producer example

Consumer application

Finally, start the consumer Spring Boot application.

Once the application starts, it will consume the message from the ActiveMQ message queue.

ActiveMQ consumer example spring boot

Also, the ActiveMQ admin console displays the consumed messages under the dequeue column.

ActiveMQ consumer example spring boot

Conclusion

In this article, we learned how to use the Apache ActiveMQ to implement the JMS producer-consumer with the Spring Boot application.

Also, we created producer and consumer JMS applications using Spring Boot.
Then, we produced the messages from the producer application to the ActiveMQ message queue.

Finally, the consumer Spring Boot application consumed the published message from the ActiveMQ JMS queue.

The example code is available on GitHub.