Apache Artemis – How to produce/consume JMS messages with SpringBoot Artemis applications.

Apache ActiveMQ Artemis is a combined feature-set of ActiveMQ/HornetQ/Apollo. It provides a non blocking architecture for an outstanding performance. So in the tutorial, JavaSampleApproach will guide how to
create JMS producer/consumer by SpringBoot Artemis applications.

Related posts:
Spring JMS with ActiveMQ – JMS Consumer and JMS Producer | Spring Boot
Spring Apache Kafka Application with SpringBoot Auto-Configuration
Spring RabbitMQ Producer/Consumer applications with SpringBoot

I. Technologies

– Java 8
– Maven 3.6.1
– Spring Tool Suite: Version 3.8.4.RELEASE
– Spring Boot: 1.5.4.RELEASE
– Apache Artemis 2.1.0

II. SpringBoot Artemis

1. SpringBoot Auto-configure

When having artemis-jms-client Artemis on the classpath, Spring Boot can auto-configure a ConnectionFactory.
We use spring.artemis.* to control Artemis configuration:


spring.artemis.mode=native
spring.artemis.host=localhost
spring.artemis.port=61616
spring.artemis.user=jsa
spring.artemis.password=12345

spring.artemis.mode has 2 mode: {NATIVE, EMBEDDED}:
NATIVE: Connect to a broker using the native Artemis protocol.
EMBEDDED: Embed the broker in the application.

2. Sending/Receiving messages

For sending message, we use: JmsTemplate jmsTemplate


@Component
public class ArtemisProducer {
	@Autowired
	JmsTemplate jmsTemplate;
	
	@Value("${jms.queue.destination}")
	String destinationQueue;
	
	public void send(String msg){
		jmsTemplate.convertAndSend(destinationQueue, msg);
	}
}

For recieved messages, we use: @JmsListener:


@Component
public class ArtemisConsumer {
	
	@JmsListener(destination = "${jms.queue.destination}")
	public void receive(String msg){
		System.out.println("Recieved Message: " + msg);
	}
}

3. SpringBoot Artemis applications

In the tutorial, we create 2 SpringBoot Artemis projects for producer/consumer:

springboot artemis - architecture

III. Practice

We create 2 SpringBoot projects {SpringBootArtemisProducer, SpringBootArtemisConsumer}:

springboot artemis - project structures

Step to do:
– Create SpringBoot projects
– Implement Artemis Producer/Consumer
– Deploy Artemis
– Run and check results

1. Create SpringBoot projects

Using SpringToolSuite, we create 2 SpringBoot projects: {SpringBootArtemisProducer, SpringBootArtemisConsumer}.

For SpringBootArtemisProducer, add dependencies:

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-artemis</artifactId>
</dependency>

<dependency>
	<groupId>org.springframework.boot</groupId>
	<artifactId>spring-boot-starter-web</artifactId>
</dependency>

For SpringBootArtemisConsumer, add dependencies:

<dependency>
	<groupId>org.springframework</groupId>
	<artifactId>spring-jms</artifactId>
</dependency>

<dependency>
    <groupId>org.apache.activemq</groupId>
    <artifactId>artemis-jms-client</artifactId>
    <version>2.1.0</version>
</dependency>

Why we don’t use artemis-jms-client 2.1.0 for SpringBootArtemisProducer?
-> At the time we do the tutorial, artemis-jms-client 2.1.0 has a bug for jmsTemplate.convertAndSend with exception:


java.lang.NoSuchMethodError: org.apache.activemq.artemis.api.core.client.ClientMessage.setUserID(Ljava/lang/Object;)Lorg/apache/activemq/artemis/api/core/Message;
	at org.apache.activemq.artemis.jms.client.ActiveMQMessageProducer.doSendx(ActiveMQMessageProducer.java:469) ~[artemis-jms-client-2.1.0.jar:2.1.0]
	at org.apache.activemq.artemis.jms.client.ActiveMQMessageProducer.send(ActiveMQMessageProducer.java:191) ~[artemis-jms-client-2.1.0.jar:2.1.0]
	at org.springframework.jms.core.JmsTemplate.doSend(JmsTemplate.java:626) ~[spring-jms-4.3.10.RELEASE.jar:4.3.10.RELEASE]
	at org.springframework.jms.core.JmsTemplate.doSend(JmsTemplate.java:597) ~[spring-jms-4.3.10.RELEASE.jar:4.3.10.RELEASE]
	at org.springframework.jms.core.JmsTemplate$4.doInJms(JmsTemplate.java:574) ~[spring-jms-4.3.10.RELEASE.jar:4.3.10.RELEASE]

Why we don’t use spring-boot-starter-artemis - version 1.5.6 (that includes artemis-jms-client 1.5.5) for Artemis consumer @JmsListener?
-> Because we got an bug:


Setup of JMS message listener invoker failed for destination 'JSA-QUEUE' - trying to recover. Cause: AMQ119019: Queue already exists JSA-QUEUE

Note:

<dependency>
	<groupId>org.springframework.boot</groupId>
	<artifactId>spring-boot-starter-artemis</artifactId>
	<version>1.5.6.RELEASE</version>
</dependency>
</pre>

<strong>EQUAL TO</strong>:

<pre class="lang:xhtml">
<dependency>
	<groupId>org.springframework</groupId>
	<artifactId>spring-jms</artifactId>
	<version>4.3.10.RELEASE</version>
</dependency>
<dependency>
	<groupId>org.apache.activemq</groupId>
	<artifactId>artemis-jms-client</artifactId>
	<version>1.5.5</version>
</dependency>

2. Implement Artemis Producer/Consumer

For above projects, open application.properties files, add Artemis configuration:


spring.artemis.mode=native
spring.artemis.host=localhost
spring.artemis.port=61616
spring.artemis.user=jsa
spring.artemis.password=12345
jms.queue.destination=JSA-QUEUE

2.1 Implement Artemis Producer

Using JmsTemplate to implement ArtemisProducer:


package com.javasampleapproach.artemis.jms;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.jms.core.JmsTemplate;
import org.springframework.stereotype.Component;

@Component
public class ArtemisProducer {
	@Autowired
	JmsTemplate jmsTemplate;
	
	@Value("${jms.queue.destination}")
	String destinationQueue;
	
	public void send(String msg){
		jmsTemplate.convertAndSend(destinationQueue, msg);
	}
}

– Create a simple RestApi for sending messages:


package com.javasampleapproach.artemis.controller;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;

import com.javasampleapproach.artemis.jms.ArtemisProducer;

@RestController
public class RestApiController {
	
	@Autowired
	ArtemisProducer producer;
	
	@RequestMapping(value="/produce")
	public String produce(@RequestParam("msg")String msg){
		producer.send(msg);
		return "Done";
	}
}

2.2 Implement Artemis Consumer

Using @JmsListener to implement ArtemisConsumer:


package com.javasampleapproach.artemis.jms;

import org.springframework.jms.annotation.JmsListener;
import org.springframework.stereotype.Component;

@Component
public class ArtemisConsumer {
	
	@JmsListener(destination = "${jms.queue.destination}")
	public void receive(String msg){
		System.out.println("Recieved Message: " + msg);
	}
}

3. Deploy Artemis

Go to Artemis download page. Download Artemis 2.1.0:

Extract apache-artemis-2.1.0-bin.zip, we have:

springboot artemis - extract

Create an Artemis broker jsa-springboot-broker by commandline:
C:\apache-artemis-2.1.0\bin>artemis create "C:\dev\jsa-springboot-broker":

springboot artemis - create artemis broker

Run the Artemis broker by commnandline: "C:\dev\jsa-springboot-broker\bin\artemis" run

springboot artemis - run

4. Run and check results

Build and Run above SpringBoot projects with commandlines: {mvn clean install, mvn spring-boot:run}

– Make a sending request: http://localhost:8080/produce?msg=JSA - SpringBoot Artemis, Hello World!. Results:

-> Use jconsole.exe, monitor message added in Artemis queue:

springboot artemis - monitoring message

-> Artemis Consumer’s Logs:


Recieved Message: JSA - SpringBoot Artemis, Hello World!

IV. Sourcecode

SpringBootArtemisProducer
SpringBootArtemisConsumer



By grokonez | July 29, 2017.

Last updated on March 16, 2021.



Related Posts


8 thoughts on “Apache Artemis – How to produce/consume JMS messages with SpringBoot Artemis applications.”

  1. hello.., great tutorial. Can you do complete end to end series on spring boot, spring data, angular with microservices
    It will be really helpful

    1. Hello Bhushan,

      In application.properies file, just modify the Artemis Connection configuration as below:

      spring.artemis.host=your_groupAddress
      spring.artemis.port=your_groupPort
      spring.artemis.user=your_groupUser
      spring.artemis.password=your_groupPassword
      

      Regards,
      JSA

      1. Thanks JavaSampleApproach for your replay, I am using static discovery server, so there is no groupAddress or groupPort.

  2. I have created project with native setting, my consumer class is receiving messages if i send from server but from producer its not receiving messages.

    1. I have exactly the same problem: consumer is not recieving the messages from the producer, only getting messages sent thru the artemis console. Did you ever find a solution ?

  3. Thanks for doing this tutorial! Before trying this project out, I had a problem with the JMS template as it could not find an implementation. It must have been my dependency management.

  4. The idea behind virtual topics is that producers send to a topic in the usual JMS way and s consumer can consume from a physical queue for a logical topic subscription, allowing many consumers to be running on many machines threads to load balance the load.

Got Something To Say:

Your email address will not be published. Required fields are marked *

*