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 artemis-jms-client libraries, which also uses javax.json API. Here is the full list of dependencies we will need:

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

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:

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.