Reinstate auto-configuration support for embedded ActiveMQ

This commit restores auto-configuration for using an Embedded broker
with ActiveMQ classic.

Contrary to its 2.7.x version, "spring-boot-starter-activemq" no longer
adds the broker for consistency with Artemis, and to keep the existing
3.x behavior. Rather than "inMemory", a "s.a.embedded.enabled"
property has been reintroduced that matches the name used by Artemis.

The documentation has been updated to mention that the broker
dependency must be added to use it.

Closes gh-38404
This commit is contained in:
Stéphane Nicoll
2024-03-19 14:17:11 -05:00
parent 1f7e7738e8
commit 3651ff87cd
12 changed files with 249 additions and 7 deletions

View File

@@ -77,6 +77,7 @@ dependencies {
optional("jakarta.persistence:jakarta.persistence-api")
optional("jakarta.servlet:jakarta.servlet-api")
optional("javax.cache:cache-api")
optional("org.apache.activemq:activemq-broker")
optional("org.apache.activemq:activemq-client")
optional("org.apache.commons:commons-dbcp2") {
exclude group: "commons-logging", module: "commons-logging"

View File

@@ -77,6 +77,7 @@ dependencies {
optional("jakarta.ws.rs:jakarta.ws.rs-api")
optional("javax.cache:cache-api")
optional("javax.money:money-api")
optional("org.apache.activemq:activemq-broker")
optional("org.apache.activemq:activemq-client")
optional("org.apache.activemq:artemis-jakarta-client") {
exclude group: "commons-logging", module: "commons-logging"

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2012-2023 the original author or authors.
* Copyright 2012-2024 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -37,6 +37,8 @@ import org.springframework.boot.context.properties.NestedConfigurationProperty;
@ConfigurationProperties(prefix = "spring.activemq")
public class ActiveMQProperties {
private static final String DEFAULT_EMBEDDED_BROKER_URL = "vm://localhost?broker.persistent=false";
private static final String DEFAULT_NETWORK_BROKER_URL = "tcp://localhost:61616";
/**
@@ -54,6 +56,8 @@ public class ActiveMQProperties {
*/
private String password;
private final Embedded embedded = new Embedded();
/**
* Time to wait before considering a close complete.
*/
@@ -99,6 +103,10 @@ public class ActiveMQProperties {
this.password = password;
}
public Embedded getEmbedded() {
return this.embedded;
}
public Duration getCloseTimeout() {
return this.closeTimeout;
}
@@ -135,9 +143,32 @@ public class ActiveMQProperties {
if (this.brokerUrl != null) {
return this.brokerUrl;
}
if (this.embedded.isEnabled()) {
return DEFAULT_EMBEDDED_BROKER_URL;
}
return DEFAULT_NETWORK_BROKER_URL;
}
/**
* Configuration for an embedded ActiveMQ broker.
*/
public static class Embedded {
/**
* Whether to enable embedded mode if the ActiveMQ Broker is available.
*/
private boolean enabled = true;
public boolean isEnabled() {
return this.enabled;
}
public void setEnabled(boolean enabled) {
this.enabled = enabled;
}
}
public static class Packages {
/**

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2012-2023 the original author or authors.
* Copyright 2012-2024 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -48,14 +48,14 @@ class ActiveMQAutoConfigurationTests {
.withConfiguration(AutoConfigurations.of(ActiveMQAutoConfiguration.class, JmsAutoConfiguration.class));
@Test
void brokerIsLocalhostByDefault() {
void brokerIsEmbeddedByDefault() {
this.contextRunner.withUserConfiguration(EmptyConfiguration.class).run((context) -> {
assertThat(context).hasSingleBean(CachingConnectionFactory.class).hasBean("jmsConnectionFactory");
CachingConnectionFactory connectionFactory = context.getBean(CachingConnectionFactory.class);
assertThat(context.getBean("jmsConnectionFactory")).isSameAs(connectionFactory);
assertThat(connectionFactory.getTargetConnectionFactory()).isInstanceOf(ActiveMQConnectionFactory.class);
assertThat(((ActiveMQConnectionFactory) connectionFactory.getTargetConnectionFactory()).getBrokerURL())
.isEqualTo("tcp://localhost:61616");
.isEqualTo("vm://localhost?broker.persistent=false");
});
}

View File

@@ -31,13 +31,15 @@ import static org.assertj.core.api.Assertions.assertThat;
*/
class ActiveMQPropertiesTests {
private static final String DEFAULT_EMBEDDED_BROKER_URL = "vm://localhost?broker.persistent=false";
private static final String DEFAULT_NETWORK_BROKER_URL = "tcp://localhost:61616";
private final ActiveMQProperties properties = new ActiveMQProperties();
@Test
void getBrokerUrlIsLocalhostByDefault() {
assertThat(this.properties.determineBrokerUrl()).isEqualTo(DEFAULT_NETWORK_BROKER_URL);
void getBrokerUrlIsEmbeddedByDefault() {
assertThat(this.properties.determineBrokerUrl()).isEqualTo(DEFAULT_EMBEDDED_BROKER_URL);
}
@Test
@@ -46,6 +48,19 @@ class ActiveMQPropertiesTests {
assertThat(this.properties.determineBrokerUrl()).isEqualTo("tcp://activemq.example.com:71717");
}
@Test
void getBrokerUrlWithEmbeddedSetToFalse() {
this.properties.getEmbedded().setEnabled(false);
assertThat(this.properties.determineBrokerUrl()).isEqualTo(DEFAULT_NETWORK_BROKER_URL);
}
@Test
void getExplicitBrokerUrlAlwaysWins() {
this.properties.setBrokerUrl("tcp://activemq.example.com:71717");
this.properties.getEmbedded().setEnabled(false);
assertThat(this.properties.determineBrokerUrl()).isEqualTo("tcp://activemq.example.com:71717");
}
@Test
void setTrustAllPackages() {
ActiveMQConnectionFactory factory = new ActiveMQConnectionFactory();

View File

@@ -12,11 +12,26 @@ Spring Boot also auto-configures the necessary infrastructure to send and receiv
== ActiveMQ "Classic" Support
When https://activemq.apache.org/components/classic[ActiveMQ "Classic"] is available on the classpath, Spring Boot can configure a `ConnectionFactory`.
If the broker is present, an embedded broker is automatically started and configured (provided no broker URL is specified through configuration and the embedded broker is not disabled in the configuration).
NOTE: If you use `spring-boot-starter-activemq`, the necessary dependencies to connect to an ActiveMQ "Classic" instance are provided, as is the Spring infrastructure to integrate with JMS.
Adding `org.apache.activemq:activemq-broker` to your application lets you use the embedded broker.
ActiveMQ "Classic" configuration is controlled by external configuration properties in `+spring.activemq.*+`.
By default, ActiveMQ "Classic" is auto-configured to use the https://activemq.apache.org/tcp-transport-reference[TCP transport], connecting by default to `tcp://localhost:61616`. The following example shows how to change the default broker URL:
If `activemq-broker` is on the classpath, ActiveMQ "Classic" is auto-configured to use the https://activemq.apache.org/vm-transport-reference.html[VM transport], which starts a broker embedded in the same JVM instance.
You can disable the embedded broker by configuring the configprop:spring.activemq.embedded.enabled[] property, as shown in the following example:
[configprops,yaml]
----
spring:
activemq:
embedded:
enabled: false
----
The embedded broker will also be disabled if you configure the broker URL, as shown in the following example:
[configprops,yaml]
----
@@ -27,6 +42,8 @@ spring:
password: "secret"
----
If you want to take full control over the embedded broker, see https://activemq.apache.org/how-do-i-embed-a-broker-inside-a-connection.html[the ActiveMQ "Classic" documentation] for further information.
By default, a `CachingConnectionFactory` wraps the native `ConnectionFactory` with sensible settings that you can control by external configuration properties in `+spring.jms.*+`:
[configprops,yaml]