How to send JMS Messages with Spring Boot

In the first tutorial about Spring Boot and Artemis MQ (JMS Messaging with Spring Boot and Artemis MQ) we have learnt how to create a JMS Producer and Consumer with an embedded ArtemisMQ server. In this second article, we will see the configuration changes needed to use a remote Artemis MQ Server.

Installing Artemis MQ Server

The first obvious step is to install ArtemisMQ from https://activemq.apache.org/artemis/download.html

Simply unzip the distribution. Next, we will create a broker configuration. From the ARTEMIS_HOME/bin folder execute:

./artemis create /home/artemis/springboot-broker --user=developer --password=developer --allow-anonymous

The above command will create a broker configuration named “springboot-broker” in the folder /home/artemis with the credentials developer/developers. Now start the broker with:

"/home/artemis/springboot-broker/bin/artemis-service" start

Creating the Producer Project

In order to start, we will need a project which uses artemis dependencies to produce JMS messages and a web Controller to trigger message dispatch. Therefore from the CLI we will execute:

$ spring init -d=artemis,web artemis-producer -x

Here is the list of dependencies that will be added:

<dependencies>
   <dependency>
      <groupId>org.springframework.boot</groupId>
      <artifactId>spring-boot-starter</artifactId>
   </dependency>
   <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>
   <dependency>
      <groupId>org.springframework.boot</groupId>
      <artifactId>spring-boot-starter-test</artifactId>
      <scope>test</scope>
   </dependency>
</dependencies>

The main Application class just bootstraps Spring Boot environment:

package com.example;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

@SpringBootApplication
public class SpringBootArtemisProducerApplication {
  public static void main(String[] args) {
    SpringApplication.run(SpringBootArtemisProducerApplication.class, args);
  }
}

The real job is done by the ArtemisProducer class, that sends a JMS message using the @org.springframework.jms.core.JmsTemplate annotation:

package com.example;

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);
  }
}

Finally, a Controller class will be responsible to send messages through the ArtemisMQProducer class:

package com.example;

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;

@RestController
public class RestApiController {
  @Autowired ArtemisProducer producer;

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

Finally, we need to set in the application.properties file the ArtemisMQ settings and the Queue name:

spring.artemis.mode=native 
spring.artemis.host=localhost 
spring.artemis.port=61616 
spring.artemis.user=developer 
spring.artemis.password=developer 
jms.queue.destination=myqueue

Creating the Consumer Project

The Consumer project will use as well artemis dependencies to consume JMS messages. Therefore from the CLI we will execute:

$ spring init -d=artemis artemis-consumer -x

On the top of artemis dependencies, we also need spring-jms (in order to compile org.springframework.jms.* packages), the artemisjms-client libraries, which also uses javax.json API. Here is the full list of dependencies we will need:

<?xml version="1.0" encoding="UTF-8"?><project>
   <dependencies>
          
      <dependency>
                
         <groupId>org.springframework.boot</groupId>
                
         <artifactId>spring-boot-starter</artifactId>
             
      </dependency>
          
      <dependency>
                
         <groupId>org.springframework</groupId>
                
         <artifactId>spring-jms</artifactId>
             
      </dependency>
          
      <dependency>
                
         <groupId>org.apache.activemq</groupId>
                
         <artifactId>artemis-jms-client</artifactId>
                
         <version>2.6.3</version>
             
      </dependency>
          
      <dependency>
                
         <groupId>org.springframework.boot</groupId>
                
         <artifactId>spring-boot-starter-test</artifactId>
                
         <scope>test</scope>
             
      </dependency>
          
      <dependency>
                
         <groupId>javax.json</groupId>
                
         <artifactId>javax.json-api</artifactId>
                
         <version>1.0</version>
             
      </dependency>
          
      <dependency>
                
         <groupId>org.glassfish</groupId>
                
         <artifactId>javax.json</artifactId>
                
         <version>1.0.4</version>
             
      </dependency>
       
   </dependencies>
    
</project>

Now let’s move to the project. Tha Application class is an ordinary Spring Boot starter class:

package com.example;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

@SpringBootApplication
public class SpringBootArtemisConsumerApplication {
  public static void main(String[] args) {
    SpringApplication.run(SpringBootArtemisConsumerApplication.class, args);
  }
}

Then we need a class which contains the @JMS Listener to receive messages:

package com.example;

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("Got Message: " + msg);
  }
}

As for the Producer, also the Consumer will need an application.properties file with the broker configuration:

spring.artemis.mode=native 
spring.artemis.host=localhost 
spring.artemis.port=61616 
spring.artemis.user=developer 
spring.artemis.password=developer 
jms.queue.destination=myqueue

Running the application

Now we can test our project. Start the Producer project with:

$ mvn spring-boot:run

Then we can send a test message:

$ curl http://localhost:8080/send?msg=hello

If you check on ArtemisMQ console (http://localhost:8161/console) you will see that the Queue named “myqueue” has 1 message now:

spring boot jms example

Now if we run the Consumer project with:

$ mvn spring-boot:run

You will see in the Console logs that the message has been received:

2018-12-19 15:13:08.867 INFO 13221 --- [ main] j.a.SpringBootArtemisConsumerApplication : Starting SpringBootArtemisConsumerApplication v0.0.1 on localhost.localdomain with PID 13221 (/home/artemis/springboot/SpringBootArtemisConsumer/target/SpringBootArtemisConsumer-0.0.1.jar started by artemis in /home/artemis/springboot/SpringBootArtemisConsumer) 2018-12-19 15:13:08.872 
INFO 13221 --- [ main] j.a.SpringBootArtemisConsumerApplication : No active profile set, falling back to default profiles: default 2018-12-19 15:13:12.471 
INFO 13221 --- [ main] j.a.SpringBootArtemisConsumerApplication : Started SpringBootArtemisConsumerApplication in 4.637 seconds (JVM running for 5.885) Recieved Message: Hello

Congratulations! You have successfully connected a remote ArtemisMQ server with a Spring Boot consumer/producer!

Troubleshooting

A common issue when connecting from a remote ArtemisMQ client is the following one:

AMQ212054: Destination address=<queue> is blocked. If the system is configured to block make sure you consume messages on this configuration.

This can happen for a variety of reasons such as:

  • If the <address-full-policy> is BLOCK and the address has reached the configured <max-size-bytes>.
  • If the <address-full-policy> is BLOCK and the <global-max-size> for all addresses is reached.
  • If the <max-disk-usage> is reached. In this case, you should, for example, increase your max-disk-usage from 90 to 100.
Found the article helpful? if so please follow us on Socials
Twitter Icon       Facebook Icon       LinkedIn Icon       Mastodon Icon