Spring JMS Artemis Example
Table of Contents
In this post I’m going to show you how to connect to ActiveMQ Artemis using Spring JMS.
In fact:
Artemis is the successor of ActiveMQ.
So if you’re starting a new project, give it a try.
Let’s take a closer look.
What is Apache ActiveMQ Artemis? #
Apache ActiveMQ Artemis a JMS Broker that is based on the HornetQ code base.
Artemis is a separate product to ActiveMQ. At the moment of writing the development team is working toward feature parity between ActiveMQ 5.x and Artemis.
The goal is that Artemis eventually becomes ActiveMQ 6.x.
In this guide, we will create a Hello World example that receives a greeting message from an Artemis JMS broker using Spring JMS, Spring Boot, and Maven.
General Project Overview #
We will use the following tools/frameworks:
- Spring JMS 5.1
- Spring Boot 2.1
- Artemis 2.6
- Maven 3.6
Our project has the following directory structure:
Maven Setup #
We build and run our example using Maven. If not already the case, download and install Apache Maven.
Let’s use Spring Initializr to generate our Maven project. Make sure to select JMS (Artemis)
as a dependency.
Click Generate Project
to generate and download the Spring Boot project template. At the root of the project, you’ll find a pom.xml
file which is the XML representation of the Maven project.
To avoid having to manage the version compatibility of the different Spring dependencies, we will inherit the defaults from the spring-boot-starter-parent
parent POM.
You can find back the exact dependency versions in Appendix F of the reference documentation. For Spring Boot 2.1.5 the Artemis dependency is version 2.6.6.
The generated project contains Spring Boot Starters that manage the different Spring dependencies.
The spring-boot-starter-artemis
dependency includes the needed dependencies for using Spring JMS in combination with Artemis.
The spring-boot-starter-test
includes the dependencies for testing Spring Boot applications with libraries that include JUnit, Hamcrest and Mockito.
We also add a dependency on artemis-junit
. It provides tools that allow us to have access to an embedded Artemis server when running our unit test.
In the plugins section, you’ll find the Spring Boot Maven Plugin. spring-boot-maven-plugin
allows us to build a single, runnable “uber-jar”. This is a convenient way to execute and transport code.
Also, the plugin allows you to start the example via a Maven command.
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.codenotfound</groupId>
<artifactId>spring-jms-artemis-hello-world</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>spring-jms-artemis-hello-world</name>
<description>Spring JMS Artemis Example</description>
<url>https://codenotfound.com/spring-jms-artemis-example.html</url>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.1.5.RELEASE</version>
<relativePath /><!-- lookup parent from repository -->
</parent>
<properties>
<java.version>11</java.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-artemis</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.apache.activemq</groupId>
<artifactId>artemis-junit</artifactId>
<version>${artemis.version}</version>
<scope>test</scope>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>
The project is for a large part identical to a previous Spring JMS ActiveMQ example. As such we will only detail the changes that are needed to connect to Artemis.
Create a Spring JMS Message Producer #
We still use an ActiveMQConnectionFactory
but this time it is part of the org.apache.activemq.artemis.jms.client
package.
We pass a brokerUrl
to the constructor as shown below.
The value is specified in the application.yml
properties file located under src/main/resources
.
package com.codenotfound.jms;
import org.apache.activemq.artemis.jms.client.ActiveMQConnectionFactory;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.jms.connection.CachingConnectionFactory;
import org.springframework.jms.core.JmsTemplate;
@Configuration
public class SenderConfig {
@Value("${artemis.broker-url}")
private String brokerUrl;
@Bean
public ActiveMQConnectionFactory senderActiveMQConnectionFactory() {
return new ActiveMQConnectionFactory(brokerUrl);
}
@Bean
public CachingConnectionFactory cachingConnectionFactory() {
return new CachingConnectionFactory(
senderActiveMQConnectionFactory());
}
@Bean
public JmsTemplate jmsTemplate() {
return new JmsTemplate(cachingConnectionFactory());
}
@Bean
public Sender sender() {
return new Sender();
}
}
Create a Spring JMS Message Consumer #
Similar to the SenderConfig
, we use the ActiveMQConnectionFactory
from the org.apache.activemq.artemis.jms.client
package.
package com.codenotfound.jms;
import org.apache.activemq.artemis.jms.client.ActiveMQConnectionFactory;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.jms.annotation.EnableJms;
import org.springframework.jms.config.DefaultJmsListenerContainerFactory;
@Configuration
@EnableJms
public class ReceiverConfig {
@Value("${artemis.broker-url}")
private String brokerUrl;
@Bean
public ActiveMQConnectionFactory receiverActiveMQConnectionFactory() {
return new ActiveMQConnectionFactory(brokerUrl);
}
@Bean
public DefaultJmsListenerContainerFactory jmsListenerContainerFactory() {
DefaultJmsListenerContainerFactory factory =
new DefaultJmsListenerContainerFactory();
factory
.setConnectionFactory(receiverActiveMQConnectionFactory());
factory.setConcurrency("3-10");
return factory;
}
@Bean
public Receiver receiver() {
return new Receiver();
}
}
And that’s it! We can now test our connection to an Artemis JMS broker.
Testing the JMS listener #
The artemis-junit package provides some JUnit rules. These make it easy to start a server for our tests.
Use the @Rule
annotation to create an EmbeddedJMSResource
that will run an Artemis server.
Then use the Sender
to send a message.
The getLatch()
on the Receiver
allows us to check if the message was received.
package com.codenotfound;
import static org.assertj.core.api.Assertions.assertThat;
import java.util.concurrent.TimeUnit;
import org.apache.activemq.artemis.junit.EmbeddedJMSResource;
import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.junit4.SpringRunner;
import com.codenotfound.jms.Receiver;
import com.codenotfound.jms.Sender;
@RunWith(SpringRunner.class)
@SpringBootTest
public class SpringJmsApplicationTest {
@Rule
public EmbeddedJMSResource resource = new EmbeddedJMSResource();
@Autowired
private Sender sender;
@Autowired
private Receiver receiver;
@Test
public void testReceive() throws Exception {
sender.send("Hello Spring JMS ActiveMQ!");
receiver.getLatch().await(10000, TimeUnit.MILLISECONDS);
assertThat(receiver.getLatch().getCount()).isEqualTo(0);
}
}
Let’s run the unit test to check if everything is working.
Open a command prompt in the root directory and execute the following Maven command.
mvn test
In the output logs, we can see that the Hello Spring JMS ActiveMQ!
greeting is received.
. ____ _ __ _ _
/\\ / ___'_ __ _ _(_)_ __ __ _ \ \ \ \
( ( )\___ | '_ | '_| | '_ \/ _` | \ \ \ \
\\/ ___)| |_)| | | | | || (_| | ) ) ) )
' |____| .__|_| |_|_| |_\__, | / / / /
=========|_|==============|___/=/_/_/_/
:: Spring Boot :: (v2.1.5.RELEASE)
2019-05-30 10:37:50.255 INFO 9420 --- [ main] c.codenotfound.SpringJmsApplicationTest : Starting SpringJmsApplicationTest on DESKTOP-2RB3C1U with PID 9420 (started by Codenotfound in C:\Users\Codenotfound\repos\spring-jms\spring-jms-artemis-hello-world)
2019-05-30 10:37:50.256 INFO 9420 --- [ main] c.codenotfound.SpringJmsApplicationTest : No active profile set, falling back to default profiles: default
2019-05-30 10:37:51.677 INFO 9420 --- [ main] c.codenotfound.SpringJmsApplicationTest : Started SpringJmsApplicationTest in 1.777 seconds (JVM running for 2.949)
2019-05-30 10:37:51.689 INFO 9420 --- [ main] o.a.a.artemis.junit.EmbeddedJMSResource : Starting EmbeddedJMSResource: embedded-jms-server
2019-05-30 10:37:51.690 INFO 9420 --- [ main] o.a.a.artemis.junit.EmbeddedJMSResource : Starting EmbeddedJMSResource: embedded-jms-server
2019-05-30 10:37:51.825 INFO 9420 --- [ main] org.apache.activemq.artemis.core.server : AMQ221000: live Message Broker is starting with configuration Broker Configuration (clustered=false,journalDirectory=data/journal,bindingsDirectory=data/bindings,largeMessagesDirectory=data/largemessages,pagingDirectory=data/paging)
2019-05-30 10:37:51.838 INFO 9420 --- [ main] org.apache.activemq.artemis.core.server : AMQ221045: libaio is not available, switching the configuration into NIO
2019-05-30 10:37:51.853 INFO 9420 --- [ main] org.apache.activemq.artemis.core.server : AMQ221057: Global Max Size is being adjusted to 1/2 of the JVM max size (-Xmx). being defined as 1.067.450.368
2019-05-30 10:37:51.871 INFO 9420 --- [ main] org.apache.activemq.artemis.core.server : AMQ221043: Protocol module found: [artemis-server]. Adding protocol support for: CORE
2019-05-30 10:37:51.934 INFO 9420 --- [ main] org.apache.activemq.artemis.core.server : AMQ221007: Server is now live
2019-05-30 10:37:51.935 INFO 9420 --- [ main] org.apache.activemq.artemis.core.server : AMQ221001: Apache ActiveMQ Artemis Message Broker version 2.6.4 [embedded-jms-server, nodeID=364c2807-82b6-11e9-83ff-bc5ff48510d9]
2019-05-30 10:37:52.266 INFO 9420 --- [ main] com.codenotfound.jms.Sender : sending message='Hello Spring JMS ActiveMQ!'
2019-05-30 10:37:52.501 WARN 9420 --- [mpl$5@2373ad99)] org.apache.activemq.artemis.core.server : AMQ222165: No Dead Letter Address configured for queue helloworld.q in AddressSettings
2019-05-30 10:37:52.502 WARN 9420 --- [mpl$5@2373ad99)] org.apache.activemq.artemis.core.server : AMQ222166: No Expiry Address configured for queue helloworld.q in AddressSettings
2019-05-30 10:37:56.709 INFO 9420 --- [enerContainer-4] com.codenotfound.jms.Receiver : received message='Hello Spring JMS ActiveMQ!'
2019-05-30 10:37:56.750 INFO 9420 --- [ main] o.a.a.artemis.junit.EmbeddedJMSResource : Stopping EmbeddedJMSResource: embedded-jms-server
2019-05-30 10:37:56.751 INFO 9420 --- [ main] o.a.a.artemis.junit.EmbeddedJMSResource : Stopping EmbeddedJMSResource: embedded-jms-server
2019-05-30 10:37:56.785 INFO 9420 --- [ main] org.apache.activemq.artemis.core.server : AMQ221002: Apache ActiveMQ Artemis Message Broker version 2.6.4 [364c2807-82b6-11e9-83ff-bc5ff48510d9] stopped, uptime 4.974 seconds
[INFO] Tests run: 1, Failures: 0, Errors: 0, Skipped: 0, Time elapsed: 7.816 s - in com.codenotfound.SpringJmsApplicationTest
[INFO]
[INFO] Results:
[INFO]
[INFO] Tests run: 1, Failures: 0, Errors: 0, Skipped: 0
[INFO]
[INFO] ------------------------------------------------------------------------
[INFO] BUILD SUCCESS
[INFO] ------------------------------------------------------------------------
[INFO] Total time: 12.435 s
[INFO] Finished at: 2019-05-30T10:37:57+02:00
[INFO] ------------------------------------------------------------------------
In this guide, we showed how to use Spring JMS to connect to ActiveMQ Artemis.
Drop a line below if this example was useful.
Or if you have a question.
Thanks!