I have a very simple Spring Boot 2.7.6 ActiveMQ Artemis app which listens for messages.
package hello;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.annotation.Bean;
import org.springframework.jms.annotation.JmsListener;
import org.springframework.jms.annotation.EnableJms;
import org.springframework.jms.config.DefaultJmsListenerContainerFactory;
import org.springframework.boot.autoconfigure.jms.DefaultJmsListenerContainerFactoryConfigurer;
import javax.jms.ConnectionFactory;
import org.springframework.jms.config.JmsListenerContainerFactory;
@SpringBootApplication
@EnableJms
public class Application {
@Bean
public JmsListenerContainerFactory<?> myFactory(ConnectionFactory connectionFactory,
DefaultJmsListenerContainerFactoryConfigurer configurer) {
DefaultJmsListenerContainerFactory factory = new DefaultJmsListenerContainerFactory();
// This provides all auto-configured defaults to this factory, including the message converter
configurer.configure(factory, connectionFactory);
// You could still override some settings if necessary.
return factory;
}
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
@JmsListener(destination = "my-queue-1")
public void listen(String in) {
System.out.println(in);
}
}
Here's the code that configures the embedded broker. I was just guessing by adding multiple acceptors. Different posts refer to addConnectorConfiguration
, but none of them seem to work so far.
package hello;
import org.apache.activemq.artemis.api.core.TransportConfiguration;
import org.apache.activemq.artemis.core.remoting.impl.netty.NettyAcceptorFactory;
import org.apache.activemq.artemis.core.remoting.impl.netty.NettyConnectorFactory;
import org.springframework.boot.autoconfigure.jms.artemis.ArtemisConfigurationCustomizer;
import org.springframework.context.annotation.Configuration;
@Configuration
public class ArtemisConfig implements ArtemisConfigurationCustomizer {
@Override
public void customize(org.apache.activemq.artemis.core.config.Configuration configuration) {
configuration.addAcceptorConfiguration("remote", "tcp://0.0.0.0:61616");
}
}
With this simple application.properties
:
spring.artemis.mode=embedded
spring.artemis.embedded.server-id=54321
spring.artemis.embedded.queues=my-queue-1
spring.artemis.embedded.enabled=true
Then I have another Spring Boot app which produces messages and sends them to the broker address.
package broker.producer;
import org.apache.activemq.artemis.jms.client.ActiveMQConnectionFactory;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.jms.core.JmsTemplate;
import org.springframework.jms.support.destination.JndiDestinationResolver;
import org.springframework.stereotype.Service;
@Service
public class JmsProducer {
@Value("${spring.jms.template.default-destination}")
private String defaultDestination;
Logger log = LoggerFactory.getLogger(JmsProducer.class);
@Bean
public ActiveMQConnectionFactory activeMQConnectionFactory() {
ActiveMQConnectionFactory activeMQConnectionFactory = new ActiveMQConnectionFactory("tcp://localhost:61616");
return activeMQConnectionFactory;
}
@Bean
public JndiDestinationResolver jndiDestinationResolver() {
return new JndiDestinationResolver();
}
@Bean
public JmsTemplate jmsTemplate() {
JmsTemplate template = new JmsTemplate();
template.setConnectionFactory(activeMQConnectionFactory());
template.setPubSubDomain(false); // false for a Queue, true for a Topic
template.setDefaultDestinationName(defaultDestination);
return template;
}
public void send(String message) {
JmsTemplate jmsTemplate = jmsTemplate();
log.info("Sending message='{}'", message);
jmsTemplate.convertAndSend(message);
log.info("Sent message='{}'", message);
}
}
Then I start each of the apps and try calling send method and I am unable to connect to the broker from the producer app due to this error:
2024-01-16 10:25:00.596 ERROR 30486 --- [nio-8080-exec-1] o.a.c.c.C.[.[.[/].[dispatcherServlet] : Servlet.service() for servlet [dispatcherServlet] in context with path [] threw exception [Request processing failed; nested exception is org.springframework.jms.UncategorizedJmsException: Uncategorized exception occurred during JMS processing; nested exception is javax.jms.JMSException: Failed to create session factory; nested exception is ActiveMQNotConnectedException[errorType=NOT_CONNECTED message=AMQ219007: Cannot connect to server(s). Tried with all available servers.]] with root cause
The producer app is able to connect to a Docker instance of ActiveMQ Artemis just fine.
For now both apps are running on the same machine, but in prod I'm hoping to have each app running in a separate pod.
I put together a very simple project as a proof-of-concept to ensure what you were doing was possible and everything worked fine for me. The embedded broker was started and accepted connections from remote clients on port 61616
.
Here's Application.java
:
package hello;
import javax.jms.ConnectionFactory;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.autoconfigure.jms.DefaultJmsListenerContainerFactoryConfigurer;
import org.springframework.context.annotation.Bean;
import org.springframework.jms.annotation.EnableJms;
import org.springframework.jms.annotation.JmsListener;
import org.springframework.jms.config.DefaultJmsListenerContainerFactory;
import org.springframework.jms.config.JmsListenerContainerFactory;
@SpringBootApplication
@EnableJms
public class Application {
@Bean
public JmsListenerContainerFactory<?> myFactory(ConnectionFactory connectionFactory,
DefaultJmsListenerContainerFactoryConfigurer configurer) {
DefaultJmsListenerContainerFactory factory = new DefaultJmsListenerContainerFactory();
// This provides all auto-configured defaults to this factory, including the message converter
configurer.configure(factory, connectionFactory);
// You could still override some settings if necessary.
return factory;
}
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
@JmsListener(destination = "my-queue-1")
public void listen(String in) {
System.out.println(in);
}
}
Here's ArtemisConfig.java
:
package hello;
import org.springframework.boot.autoconfigure.jms.artemis.ArtemisConfigurationCustomizer;
import org.springframework.context.annotation.Configuration;
@Configuration
public class ArtemisConfig implements ArtemisConfigurationCustomizer {
@Override
public void customize(org.apache.activemq.artemis.core.config.Configuration configuration) {
try {
configuration.addAcceptorConfiguration("remote", "tcp://0.0.0.0:61616");
} catch (Exception e) {
e.printStackTrace();
}
}
}
Here's my application.properties
:
spring.artemis.mode=embedded
spring.artemis.embedded.server-id=54321
spring.artemis.embedded.queues=my-queue-1
spring.artemis.embedded.enabled=true
Finally, here's my pom.xml
:
<?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 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.7.6</version>
<relativePath/>
</parent>
<groupId>com.example</groupId>
<artifactId>spring-boot-customized-activemq-artemis</artifactId>
<version>0.0.1-SNAPSHOT</version>
<properties>
<java.version>17</java.version>
<spring.version>2.7.6</spring.version>
<activemq.artemis.version>2.19.1</activemq.artemis.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-artemis</artifactId>
</dependency>
<dependency>
<groupId>org.apache.activemq</groupId>
<artifactId>artemis-jms-server</artifactId>
<version>${activemq.artemis.version}</version>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<version>${spring.version}</version>
</plugin>
</plugins>
</build>
</project>
I start the application like so:
mvn spring-boot:run
I see logging like this:
...
... AMQ221020: Started EPOLL Acceptor at 0.0.0.0:61616 for protocols [CORE]
... AMQ221007: Server is now live
...
I can send a message to the broker from another application and the JmsListener
receives it.
I uploaded the project to GitHub.