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:
<?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:
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.