Skip to content

Commit 3651ff8

Browse files
committed
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
1 parent 1f7e773 commit 3651ff8

File tree

12 files changed

+249
-7
lines changed

12 files changed

+249
-7
lines changed

spring-boot-project/spring-boot-actuator-autoconfigure/build.gradle

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -77,6 +77,7 @@ dependencies {
7777
optional("jakarta.persistence:jakarta.persistence-api")
7878
optional("jakarta.servlet:jakarta.servlet-api")
7979
optional("javax.cache:cache-api")
80+
optional("org.apache.activemq:activemq-broker")
8081
optional("org.apache.activemq:activemq-client")
8182
optional("org.apache.commons:commons-dbcp2") {
8283
exclude group: "commons-logging", module: "commons-logging"

spring-boot-project/spring-boot-autoconfigure/build.gradle

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -77,6 +77,7 @@ dependencies {
7777
optional("jakarta.ws.rs:jakarta.ws.rs-api")
7878
optional("javax.cache:cache-api")
7979
optional("javax.money:money-api")
80+
optional("org.apache.activemq:activemq-broker")
8081
optional("org.apache.activemq:activemq-client")
8182
optional("org.apache.activemq:artemis-jakarta-client") {
8283
exclude group: "commons-logging", module: "commons-logging"

spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/jms/activemq/ActiveMQProperties.java

Lines changed: 32 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2012-2023 the original author or authors.
2+
* Copyright 2012-2024 the original author or authors.
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -37,6 +37,8 @@
3737
@ConfigurationProperties(prefix = "spring.activemq")
3838
public class ActiveMQProperties {
3939

40+
private static final String DEFAULT_EMBEDDED_BROKER_URL = "vm://localhost?broker.persistent=false";
41+
4042
private static final String DEFAULT_NETWORK_BROKER_URL = "tcp://localhost:61616";
4143

4244
/**
@@ -54,6 +56,8 @@ public class ActiveMQProperties {
5456
*/
5557
private String password;
5658

59+
private final Embedded embedded = new Embedded();
60+
5761
/**
5862
* Time to wait before considering a close complete.
5963
*/
@@ -99,6 +103,10 @@ public void setPassword(String password) {
99103
this.password = password;
100104
}
101105

106+
public Embedded getEmbedded() {
107+
return this.embedded;
108+
}
109+
102110
public Duration getCloseTimeout() {
103111
return this.closeTimeout;
104112
}
@@ -135,9 +143,32 @@ String determineBrokerUrl() {
135143
if (this.brokerUrl != null) {
136144
return this.brokerUrl;
137145
}
146+
if (this.embedded.isEnabled()) {
147+
return DEFAULT_EMBEDDED_BROKER_URL;
148+
}
138149
return DEFAULT_NETWORK_BROKER_URL;
139150
}
140151

152+
/**
153+
* Configuration for an embedded ActiveMQ broker.
154+
*/
155+
public static class Embedded {
156+
157+
/**
158+
* Whether to enable embedded mode if the ActiveMQ Broker is available.
159+
*/
160+
private boolean enabled = true;
161+
162+
public boolean isEnabled() {
163+
return this.enabled;
164+
}
165+
166+
public void setEnabled(boolean enabled) {
167+
this.enabled = enabled;
168+
}
169+
170+
}
171+
141172
public static class Packages {
142173

143174
/**

spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/jms/activemq/ActiveMQAutoConfigurationTests.java

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2012-2023 the original author or authors.
2+
* Copyright 2012-2024 the original author or authors.
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -48,14 +48,14 @@ class ActiveMQAutoConfigurationTests {
4848
.withConfiguration(AutoConfigurations.of(ActiveMQAutoConfiguration.class, JmsAutoConfiguration.class));
4949

5050
@Test
51-
void brokerIsLocalhostByDefault() {
51+
void brokerIsEmbeddedByDefault() {
5252
this.contextRunner.withUserConfiguration(EmptyConfiguration.class).run((context) -> {
5353
assertThat(context).hasSingleBean(CachingConnectionFactory.class).hasBean("jmsConnectionFactory");
5454
CachingConnectionFactory connectionFactory = context.getBean(CachingConnectionFactory.class);
5555
assertThat(context.getBean("jmsConnectionFactory")).isSameAs(connectionFactory);
5656
assertThat(connectionFactory.getTargetConnectionFactory()).isInstanceOf(ActiveMQConnectionFactory.class);
5757
assertThat(((ActiveMQConnectionFactory) connectionFactory.getTargetConnectionFactory()).getBrokerURL())
58-
.isEqualTo("tcp://localhost:61616");
58+
.isEqualTo("vm://localhost?broker.persistent=false");
5959
});
6060
}
6161

spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/jms/activemq/ActiveMQPropertiesTests.java

Lines changed: 17 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -31,13 +31,15 @@
3131
*/
3232
class ActiveMQPropertiesTests {
3333

34+
private static final String DEFAULT_EMBEDDED_BROKER_URL = "vm://localhost?broker.persistent=false";
35+
3436
private static final String DEFAULT_NETWORK_BROKER_URL = "tcp://localhost:61616";
3537

3638
private final ActiveMQProperties properties = new ActiveMQProperties();
3739

3840
@Test
39-
void getBrokerUrlIsLocalhostByDefault() {
40-
assertThat(this.properties.determineBrokerUrl()).isEqualTo(DEFAULT_NETWORK_BROKER_URL);
41+
void getBrokerUrlIsEmbeddedByDefault() {
42+
assertThat(this.properties.determineBrokerUrl()).isEqualTo(DEFAULT_EMBEDDED_BROKER_URL);
4143
}
4244

4345
@Test
@@ -46,6 +48,19 @@ void getBrokerUrlUseExplicitBrokerUrl() {
4648
assertThat(this.properties.determineBrokerUrl()).isEqualTo("tcp://activemq.example.com:71717");
4749
}
4850

51+
@Test
52+
void getBrokerUrlWithEmbeddedSetToFalse() {
53+
this.properties.getEmbedded().setEnabled(false);
54+
assertThat(this.properties.determineBrokerUrl()).isEqualTo(DEFAULT_NETWORK_BROKER_URL);
55+
}
56+
57+
@Test
58+
void getExplicitBrokerUrlAlwaysWins() {
59+
this.properties.setBrokerUrl("tcp://activemq.example.com:71717");
60+
this.properties.getEmbedded().setEnabled(false);
61+
assertThat(this.properties.determineBrokerUrl()).isEqualTo("tcp://activemq.example.com:71717");
62+
}
63+
4964
@Test
5065
void setTrustAllPackages() {
5166
ActiveMQConnectionFactory factory = new ActiveMQConnectionFactory();

spring-boot-project/spring-boot-docs/src/docs/antora/modules/reference/pages/messaging/jms.adoc

Lines changed: 18 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,11 +12,26 @@ Spring Boot also auto-configures the necessary infrastructure to send and receiv
1212
== ActiveMQ "Classic" Support
1313

1414
When https://activemq.apache.org/components/classic[ActiveMQ "Classic"] is available on the classpath, Spring Boot can configure a `ConnectionFactory`.
15+
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).
1516

1617
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.
18+
Adding `org.apache.activemq:activemq-broker` to your application lets you use the embedded broker.
1719

1820
ActiveMQ "Classic" configuration is controlled by external configuration properties in `+spring.activemq.*+`.
19-
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:
21+
22+
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.
23+
24+
You can disable the embedded broker by configuring the configprop:spring.activemq.embedded.enabled[] property, as shown in the following example:
25+
26+
[configprops,yaml]
27+
----
28+
spring:
29+
activemq:
30+
embedded:
31+
enabled: false
32+
----
33+
34+
The embedded broker will also be disabled if you configure the broker URL, as shown in the following example:
2035

2136
[configprops,yaml]
2237
----
@@ -27,6 +42,8 @@ spring:
2742
password: "secret"
2843
----
2944

45+
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.
46+
3047
By default, a `CachingConnectionFactory` wraps the native `ConnectionFactory` with sensible settings that you can control by external configuration properties in `+spring.jms.*+`:
3148

3249
[configprops,yaml]
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
plugins {
2+
id "java"
3+
id "org.springframework.boot.conventions"
4+
}
5+
6+
description = "Spring Boot Actuator ActiveMQ Embedded smoke test"
7+
8+
dependencies {
9+
implementation(project(":spring-boot-project:spring-boot-starters:spring-boot-starter-activemq"))
10+
11+
runtimeOnly("org.apache.activemq:activemq-broker")
12+
13+
testImplementation(project(":spring-boot-project:spring-boot-starters:spring-boot-starter-test"))
14+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
/*
2+
* Copyright 2012-2024 the original author or authors.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* https://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
package smoketest.activemq.embedded;
18+
19+
import org.springframework.jms.annotation.JmsListener;
20+
import org.springframework.stereotype.Component;
21+
22+
@Component
23+
public class Consumer {
24+
25+
@JmsListener(destination = "sample.queue")
26+
public void receiveQueue(String text) {
27+
System.out.println(text);
28+
}
29+
30+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
/*
2+
* Copyright 2012-2024 the original author or authors.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* https://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
package smoketest.activemq.embedded;
18+
19+
import jakarta.jms.Queue;
20+
21+
import org.springframework.beans.factory.annotation.Autowired;
22+
import org.springframework.boot.CommandLineRunner;
23+
import org.springframework.jms.core.JmsMessagingTemplate;
24+
import org.springframework.stereotype.Component;
25+
26+
@Component
27+
public class Producer implements CommandLineRunner {
28+
29+
@Autowired
30+
private JmsMessagingTemplate jmsMessagingTemplate;
31+
32+
@Autowired
33+
private Queue queue;
34+
35+
@Override
36+
public void run(String... args) throws Exception {
37+
send("Sample message");
38+
System.out.println("Message was sent to the Queue");
39+
}
40+
41+
public void send(String msg) {
42+
this.jmsMessagingTemplate.convertAndSend(this.queue, msg);
43+
}
44+
45+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
/*
2+
* Copyright 2012-2024 the original author or authors.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* https://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
package smoketest.activemq.embedded;
18+
19+
import jakarta.jms.Queue;
20+
import org.apache.activemq.command.ActiveMQQueue;
21+
22+
import org.springframework.boot.SpringApplication;
23+
import org.springframework.boot.autoconfigure.SpringBootApplication;
24+
import org.springframework.context.annotation.Bean;
25+
import org.springframework.jms.annotation.EnableJms;
26+
27+
@SpringBootApplication
28+
@EnableJms
29+
public class SampleActiveMQApplication {
30+
31+
@Bean
32+
public Queue queue() {
33+
return new ActiveMQQueue("sample.queue");
34+
}
35+
36+
public static void main(String[] args) {
37+
SpringApplication.run(SampleActiveMQApplication.class, args);
38+
}
39+
40+
}

0 commit comments

Comments
 (0)