DEV Community

loizenai
loizenai

Posted on

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

https://grokonez.com/spring-framework/spring-jms/apache-artemis-produceconsume-jms-messages-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:

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}

-> 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

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

Top comments (0)