Apache Artemis - How to produce/consume JMS messages with SpringBoot Artemis applications.
Tags: apache, artemis, jms, springboot
Published: 2021-03-16 10:23:34

https://grokonez.com/spring-framework/spring-jms/apache-artemis-produceconsume-jms-messages-springboot-artemis-applications

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

Related posts:
- <a href="https://grokonez.com/spring-framework/spring-boot/use-spring-jms-activemq-jms-consumer-jms-producer-spring-boot">Spring JMS with ActiveMQ – JMS Consumer and JMS Producer | Spring Boot</a>
- <a href="https://grokonez.com/spring-framework/spring-boot/start-spring-apache-kafka-application-springboot">Spring Apache Kafka Application with SpringBoot Auto-Configuration</a>
- <a href="https://grokonez.com/spring-framework/spring-boot/create-spring-rabbitmq-producerconsumer-application-springboot">Spring RabbitMQ Producer/Consumer applications with SpringBoot</a>

<!--more-->
<h2>I. Technologies</h2>
– 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
<h2>II. SpringBoot Artemis</h2>
<h3>1. SpringBoot Auto-configure</h3>
When having <code>artemis-jms-client</code> Artemis on the classpath, Spring Boot can auto-configure a <strong>ConnectionFactory</strong>.
We use <code>spring.artemis.*</code> to control Artemis configuration:

<pre><code class="language-javascript">
spring.artemis.mode=native
spring.artemis.host=localhost
spring.artemis.port=61616
spring.artemis.user=jsa
spring.artemis.password=12345
</code></pre>

<code>spring.artemis.mode</code> has 2 mode: {<strong>NATIVE</strong>, <strong>EMBEDDED</strong>}:
- <strong>NATIVE</strong>: Connect to a broker using the native Artemis protocol.
- <strong>EMBEDDED</strong>: Embed the broker in the application.
<h3>2. Sending/Receiving messages</h3>
For sending message, we use: <code>JmsTemplate jmsTemplate</code>

<pre><code class="language-java">
@Component
public class ArtemisProducer {
	@Autowired
	JmsTemplate jmsTemplate;
	
	@Value("${jms.queue.destination}")
	String destinationQueue;
	
	public void send(String msg){
		jmsTemplate.convertAndSend(destinationQueue, msg);
	}
}
</code></pre>

For recieved messages, we use: <code>@JmsListener</code>:

<pre><code class="language-java">
@Component
public class ArtemisConsumer {
	
	@JmsListener(destination = "${jms.queue.destination}")
	public void receive(String msg){
		System.out.println("Recieved Message: " + msg);
	}
}
</code></pre>
<h2>3. SpringBoot Artemis applications</h2>
In the tutorial, we create 2 SpringBoot Artemis projects for producer/consumer:

<img src="https://grokonez.com/wp-content/uploads/2017/07/springboot-artemis-architecture.png" alt="springboot artemis - architecture" width="599" height="216" class="alignnone size-full wp-image-7061" />
<h2>III. Practice</h2>
We create 2 SpringBoot projects {<strong>SpringBootArtemisProducer</strong>, <strong>SpringBootArtemisConsumer</strong>}:

<img src="https://grokonez.com/wp-content/uploads/2017/07/springboot-artemis-project-structures.png" alt="springboot artemis - project structures" width="740" height="209" class="alignnone size-full wp-image-7062" />

<strong>Step to do</strong>:
- Create SpringBoot projects
- Implement Artemis Producer/Consumer
- Deploy Artemis
- Run and check results
<h3>1. Create SpringBoot projects</h3>
Using <strong>SpringToolSuite</strong>, we create 2 SpringBoot projects: {<strong>SpringBootArtemisProducer</strong>, <strong>SpringBootArtemisConsumer</strong>}.

For <strong>SpringBootArtemisProducer</strong>, add dependencies:

<pre><code class="language-html">&lt;dependency&gt;
    &lt;groupId&gt;org.springframework.boot&lt;/groupId&gt;
    &lt;artifactId&gt;spring-boot-starter-artemis&lt;/artifactId&gt;
&lt;/dependency&gt;

&lt;dependency&gt;
	&lt;groupId&gt;org.springframework.boot&lt;/groupId&gt;
	&lt;artifactId&gt;spring-boot-starter-web&lt;/artifactId&gt;
&lt;/dependency&gt;</code></pre>

For <strong>SpringBootArtemisConsumer</strong>, add dependencies:

<pre><code class="language-html">&lt;dependency&gt;
	&lt;groupId&gt;org.springframework&lt;/groupId&gt;
	&lt;artifactId&gt;spring-jms&lt;/artifactId&gt;
&lt;/dependency&gt;

&lt;dependency&gt;
    &lt;groupId&gt;org.apache.activemq&lt;/groupId&gt;
    &lt;artifactId&gt;artemis-jms-client&lt;/artifactId&gt;
    &lt;version&gt;2.1.0&lt;/version&gt;
&lt;/dependency&gt;</code></pre>

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

<pre><code class="language-javascript">
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]
</code></pre>

Why we don't use <code>spring-boot-starter-artemis - version 1.5.6</code> (that includes <code>artemis-jms-client 1.5.5</code>) for Artemis consumer <code>@JmsListener</code>?
-> Because we got an bug:
<pre><code class="language-java">
Setup of JMS message listener invoker failed for destination 'JSA-QUEUE' - trying to recover. Cause: AMQ119019: Queue already exists JSA-QUEUE
</code></pre>

<strong>Note</strong>:  
<pre><code class="language-html">&lt;dependency&gt;
	&lt;groupId&gt;org.springframework.boot&lt;/groupId&gt;
	&lt;artifactId&gt;spring-boot-starter-artemis&lt;/artifactId&gt;
	&lt;version&gt;1.5.6.RELEASE&lt;/version&gt;
&lt;/dependency&gt;
&lt;/pre&gt;

&lt;strong&gt;EQUAL TO&lt;/strong&gt;:

&lt;pre class=&quot;lang:xhtml&quot;&gt;
&lt;dependency&gt;
	&lt;groupId&gt;org.springframework&lt;/groupId&gt;
	&lt;artifactId&gt;spring-jms&lt;/artifactId&gt;
	&lt;version&gt;4.3.10.RELEASE&lt;/version&gt;
&lt;/dependency&gt;
&lt;dependency&gt;
	&lt;groupId&gt;org.apache.activemq&lt;/groupId&gt;
	&lt;artifactId&gt;artemis-jms-client&lt;/artifactId&gt;
	&lt;version&gt;1.5.5&lt;/version&gt;
&lt;/dependency&gt;</code></pre>
<h3>2. Implement Artemis Producer/Consumer</h3>
For above projects, open <strong>application.properties</strong> files, add Artemis configuration:

<pre><code class="language-javascript">
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
</code></pre>
<h4>2.1 Implement Artemis Producer</h4>
Using <code>JmsTemplate</code> to implement <code>ArtemisProducer</code>:

<pre><code class="language-java">
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);
	}
}</code></pre>

- Create a simple RestApi for sending messages:

<pre><code class="language-java">
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";
	}
}
</code></pre>
<h4>2.2 Implement Artemis Consumer</h4>
Using <code>@JmsListener</code> to implement <strong>ArtemisConsumer</strong>:

<pre><code class="language-java">
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);
	}
}
</code></pre>
<h3>3. Deploy Artemis</h3>
Go to <a href="https://activemq.apache.org/artemis/download.html">Artemis download page</a>. Download Artemis 2.1.0:

<img src="https://grokonez.com/wp-content/uploads/2017/07/springboot-artemis-download-1.png" alt="" width="719" height="169" class="alignnone size-full wp-image-7075" />

Extract <strong>apache-artemis-2.1.0-bin.zip</strong>, we have: 

<img src="https://grokonez.com/wp-content/uploads/2017/07/springboot-artemis-extract.png" alt="springboot artemis - extract" width="492" height="233" class="alignnone size-full wp-image-7064" />

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

<img src="https://grokonez.com/wp-content/uploads/2017/07/springboot-artemis-create-artemis-broker.png" alt="springboot artemis - create artemis broker" width="711" height="462" class="alignnone size-full wp-image-7065" />

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

<img src="https://grokonez.com/wp-content/uploads/2017/07/springboot-artemis-run.png" alt="springboot artemis - run" width="686" height="440" class="alignnone size-full wp-image-7066" />
<h3>4. Run and check results</h3>
Build and Run above SpringBoot projects with commandlines: {<code>mvn clean install</code>, <code>mvn spring-boot:run</code>}

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

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

<img src="https://grokonez.com/wp-content/uploads/2017/07/springboot-artemis-monitoring-message.png" alt="springboot artemis - monitoring message" width="552" height="632" class="alignnone size-full wp-image-7067" />

-> Artemis Consumer's Logs:

<pre><code class="language-java">
Recieved Message: JSA - SpringBoot Artemis, Hello World!
</code></pre>
<h2>IV. Sourcecode</h2>
<a href="https://grokonez.com/wp-content/uploads/2017/07/SpringBootArtemisProducer.zip">SpringBootArtemisProducer</a>
<a href="https://grokonez.com/wp-content/uploads/2017/07/SpringBootArtemisConsumer.zip">SpringBootArtemisConsumer</a>

https://grokonez.com/spring-framework/spring-jms/apache-artemis-produceconsume-jms-messages-springboot-artemis-applications