Skip to content

Commit c3591a7

Browse files
authored
Add ServiceBus Service Connection for Docker Compose and Testcontainers (#44019)
1 parent ca563b4 commit c3591a7

File tree

26 files changed

+800
-36
lines changed

26 files changed

+800
-36
lines changed

eng/versioning/external_dependencies.txt

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -397,6 +397,8 @@ springboot4_org.testcontainers:junit-jupiter;1.21.3
397397
springboot4_org.testcontainers:azure;1.21.3
398398
springboot4_jakarta.annotation:jakarta.annotation-api;3.0.0
399399
springboot4_ch.qos.logback:logback-classic;1.5.25
400+
springboot4_org.awaitility:awaitility;4.3.0
401+
springboot4_com.microsoft.sqlserver:mssql-jdbc;13.2.1.jre11
400402
# Used for Spring version updates
401403
springboot4_org.springframework.boot:spring-boot-dependencies;4.0.2
402404
springboot4_org.springframework.cloud:spring-cloud-dependencies;2025.1.0

sdk/spring/CHANGELOG.md

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,31 @@
11
# Release History
22

3+
## 7.1.0 (Not Released)
4+
5+
### Spring Cloud Azure Autoconfigure
6+
7+
This section includes changes in `spring-cloud-azure-autoconfigure` module.
8+
9+
#### New Features
10+
11+
- Add ConnectionDetails for ServiceBus. [#44019](https://github.com/Azure/azure-sdk-for-java/pull/44019).
12+
13+
### Spring Cloud Azure Docker Compose
14+
15+
This section includes changes in `spring-cloud-azure-docker-compose` module.
16+
17+
#### New Features
18+
19+
- Add ServiceBusDockerComposeConnectionDetailsFactory. [#44019](https://github.com/Azure/azure-sdk-for-java/pull/44019).
20+
21+
### Spring Cloud Azure Test Containers
22+
23+
This section includes changes in `spring-cloud-azure-testcontainers` module.
24+
25+
#### New Features
26+
27+
- Add ServiceBusContainerConnectionDetailsFactory. [#44019](https://github.com/Azure/azure-sdk-for-java/pull/44019).
28+
329
## 7.0.0 (2026-02-03)
430
- This release is compatible with Spring Boot 4.0.0-4.0.2. (Note: 4.0.x (x>2) should be supported, but they aren't tested with this release.)
531
- This release is compatible with Spring Cloud 2025.1.0. (Note: 2025.1.x (x>0) should be supported, but they aren't tested with this release.)

sdk/spring/spring-cloud-azure-autoconfigure/src/main/java/com/azure/spring/cloud/autoconfigure/implementation/servicebus/AzureServiceBusAutoConfiguration.java

Lines changed: 2 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -6,12 +6,10 @@
66
import com.azure.messaging.servicebus.ServiceBusClientBuilder;
77
import com.azure.spring.cloud.autoconfigure.implementation.AzureServiceConfigurationBase;
88
import com.azure.spring.cloud.autoconfigure.implementation.context.properties.AzureGlobalProperties;
9-
import com.azure.spring.cloud.autoconfigure.implementation.servicebus.properties.AzureServiceBusProperties;
9+
import com.azure.spring.cloud.autoconfigure.implementation.servicebus.properties.AzureServiceBusPropertiesConfiguration;
1010
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
1111
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
1212
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
13-
import org.springframework.boot.context.properties.ConfigurationProperties;
14-
import org.springframework.context.annotation.Bean;
1513
import org.springframework.context.annotation.Import;
1614

1715
/**
@@ -22,22 +20,16 @@
2220
@ConditionalOnClass(ServiceBusClientBuilder.class)
2321
@ConditionalOnProperty(value = "spring.cloud.azure.servicebus.enabled", havingValue = "true", matchIfMissing = true)
2422
@Import({
23+
AzureServiceBusPropertiesConfiguration.class,
2524
AzureServiceBusClientBuilderConfiguration.class,
2625
AzureServiceBusProducerClientConfiguration.class,
2726
AzureServiceBusConsumerClientConfiguration.class,
2827
AzureServiceBusProcessorClientConfiguration.class
2928
})
3029
public class AzureServiceBusAutoConfiguration extends AzureServiceConfigurationBase {
3130

32-
3331
AzureServiceBusAutoConfiguration(AzureGlobalProperties azureGlobalProperties) {
3432
super(azureGlobalProperties);
3533
}
3634

37-
@Bean
38-
@ConfigurationProperties(AzureServiceBusProperties.PREFIX)
39-
AzureServiceBusProperties azureServiceBusProperties() {
40-
return loadProperties(getAzureGlobalProperties(), new AzureServiceBusProperties());
41-
}
42-
4335
}

sdk/spring/spring-cloud-azure-autoconfigure/src/main/java/com/azure/spring/cloud/autoconfigure/implementation/servicebus/AzureServiceBusClientBuilderConfiguration.java

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,24 +4,27 @@
44
package com.azure.spring.cloud.autoconfigure.implementation.servicebus;
55

66
import com.azure.messaging.servicebus.ServiceBusClientBuilder;
7-
import com.azure.spring.cloud.autoconfigure.implementation.condition.ConditionalOnAnyProperty;
87
import com.azure.spring.cloud.autoconfigure.implementation.servicebus.properties.AzureServiceBusProperties;
8+
import com.azure.spring.cloud.autoconfigure.implementation.servicebus.properties.AzureServiceBusPropertiesConfiguration;
99
import com.azure.spring.cloud.core.customizer.AzureServiceClientBuilderCustomizer;
1010
import com.azure.spring.cloud.core.implementation.util.AzureSpringIdentifier;
1111
import com.azure.spring.cloud.core.provider.connectionstring.ServiceConnectionStringProvider;
1212
import com.azure.spring.cloud.core.provider.connectionstring.StaticConnectionStringProvider;
1313
import com.azure.spring.cloud.core.service.AzureServiceType;
1414
import com.azure.spring.cloud.service.implementation.servicebus.factory.ServiceBusClientBuilderFactory;
1515
import org.springframework.beans.factory.ObjectProvider;
16+
import org.springframework.boot.autoconfigure.condition.ConditionalOnBean;
1617
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
1718
import org.springframework.boot.autoconfigure.condition.ConditionalOnExpression;
1819
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
1920
import org.springframework.context.annotation.Bean;
2021
import org.springframework.context.annotation.Configuration;
22+
import org.springframework.context.annotation.Import;
2123

2224
@Configuration(proxyBeanMethods = false)
25+
@Import(AzureServiceBusPropertiesConfiguration.class)
2326
@ConditionalOnClass(ServiceBusClientBuilder.class)
24-
@ConditionalOnAnyProperty(prefix = "spring.cloud.azure.servicebus", name = { "connection-string", "namespace" })
27+
@ConditionalOnBean(AzureServiceBusProperties.class)
2528
class AzureServiceBusClientBuilderConfiguration {
2629

2730
private final AzureServiceBusProperties serviceBusProperties;

sdk/spring/spring-cloud-azure-autoconfigure/src/main/java/com/azure/spring/cloud/autoconfigure/implementation/servicebus/AzureServiceBusMessagingAutoConfiguration.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,8 +7,8 @@
77
import com.azure.messaging.servicebus.ServiceBusClientBuilder;
88
import com.azure.messaging.servicebus.ServiceBusMessage;
99
import com.azure.messaging.servicebus.ServiceBusReceivedMessage;
10-
import com.azure.spring.cloud.autoconfigure.implementation.condition.ConditionalOnAnyProperty;
1110
import com.azure.spring.cloud.autoconfigure.implementation.servicebus.properties.AzureServiceBusProperties;
11+
import com.azure.spring.cloud.autoconfigure.implementation.servicebus.properties.AzureServiceBusPropertiesConfiguration;
1212
import com.azure.spring.cloud.core.customizer.AzureServiceClientBuilderCustomizer;
1313
import com.azure.spring.cloud.core.implementation.credential.resolver.AzureTokenCredentialResolver;
1414
import com.azure.spring.cloud.core.provider.connectionstring.ServiceConnectionStringProvider;
@@ -58,10 +58,10 @@
5858
@Configuration(proxyBeanMethods = false)
5959
@ConditionalOnClass(ServiceBusTemplate.class)
6060
@ConditionalOnProperty(value = "spring.cloud.azure.servicebus.enabled", havingValue = "true", matchIfMissing = true)
61-
@ConditionalOnAnyProperty(prefix = "spring.cloud.azure.servicebus", name = { "connection-string", "namespace" })
6261
@ConditionalOnBean(AzureServiceBusProperties.class)
6362
@AutoConfigureAfter(AzureServiceBusAutoConfiguration.class)
6463
@Import({
64+
AzureServiceBusPropertiesConfiguration.class,
6565
AzureServiceBusMessagingAutoConfiguration.ServiceBusTemplateConfiguration.class,
6666
AzureServiceBusMessagingAutoConfiguration.ProcessorContainerConfiguration.class
6767
})
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
// Copyright (c) Microsoft Corporation. All rights reserved.
2+
// Licensed under the MIT License.
3+
4+
package com.azure.spring.cloud.autoconfigure.implementation.servicebus.properties;
5+
6+
import org.springframework.boot.autoconfigure.service.connection.ConnectionDetails;
7+
8+
public interface AzureServiceBusConnectionDetails extends ConnectionDetails {
9+
10+
String getConnectionString();
11+
12+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
// Copyright (c) Microsoft Corporation. All rights reserved.
2+
// Licensed under the MIT License.
3+
4+
package com.azure.spring.cloud.autoconfigure.implementation.servicebus.properties;
5+
6+
import org.springframework.boot.context.properties.EnableConfigurationProperties;
7+
import org.springframework.context.annotation.Import;
8+
9+
@Import({
10+
ConfigurationWithConnectionDetailsBean.class,
11+
ConfigurationWithoutConnectionDetailsBean.class,
12+
})
13+
@EnableConfigurationProperties
14+
public class AzureServiceBusPropertiesConfiguration {
15+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
// Copyright (c) Microsoft Corporation. All rights reserved.
2+
// Licensed under the MIT License.
3+
4+
package com.azure.spring.cloud.autoconfigure.implementation.servicebus.properties;
5+
6+
import com.azure.spring.cloud.autoconfigure.implementation.context.properties.AzureGlobalProperties;
7+
import com.azure.spring.cloud.autoconfigure.implementation.properties.utils.AzureGlobalPropertiesUtils;
8+
import org.springframework.boot.autoconfigure.condition.ConditionalOnBean;
9+
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
10+
import org.springframework.boot.autoconfigure.service.connection.ConnectionDetails;
11+
import org.springframework.boot.context.properties.bind.BindResult;
12+
import org.springframework.boot.context.properties.bind.Bindable;
13+
import org.springframework.boot.context.properties.bind.Binder;
14+
import org.springframework.context.annotation.Bean;
15+
import org.springframework.core.env.Environment;
16+
17+
@ConditionalOnClass(ConnectionDetails.class)
18+
@ConditionalOnBean(AzureServiceBusConnectionDetails.class)
19+
class ConfigurationWithConnectionDetailsBean {
20+
21+
private final Environment environment;
22+
private final AzureGlobalProperties globalProperties;
23+
private final AzureServiceBusConnectionDetails connectionDetails;
24+
25+
ConfigurationWithConnectionDetailsBean(
26+
Environment environment,
27+
AzureGlobalProperties globalProperties,
28+
AzureServiceBusConnectionDetails connectionDetails) {
29+
this.environment = environment;
30+
this.globalProperties = globalProperties;
31+
this.connectionDetails = connectionDetails;
32+
}
33+
34+
@Bean
35+
AzureServiceBusProperties azureServiceBusProperties() {
36+
AzureServiceBusProperties propertiesLoadFromGlobalProperties =
37+
AzureGlobalPropertiesUtils.loadProperties(globalProperties, new AzureServiceBusProperties());
38+
BindResult<AzureServiceBusProperties> bindResult = Binder.get(environment)
39+
.bind(AzureServiceBusProperties.PREFIX, Bindable.ofInstance(propertiesLoadFromGlobalProperties));
40+
AzureServiceBusProperties properties = bindResult.isBound() ? bindResult.get()
41+
: propertiesLoadFromGlobalProperties;
42+
properties.setConnectionString(connectionDetails.getConnectionString());
43+
return properties;
44+
}
45+
46+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
// Copyright (c) Microsoft Corporation. All rights reserved.
2+
// Licensed under the MIT License.
3+
4+
package com.azure.spring.cloud.autoconfigure.implementation.servicebus.properties;
5+
6+
import com.azure.spring.cloud.autoconfigure.implementation.condition.ConditionalOnAnyProperty;
7+
import com.azure.spring.cloud.autoconfigure.implementation.context.properties.AzureGlobalProperties;
8+
import com.azure.spring.cloud.autoconfigure.implementation.properties.utils.AzureGlobalPropertiesUtils;
9+
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
10+
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
11+
import org.springframework.boot.context.properties.ConfigurationProperties;
12+
import org.springframework.context.annotation.Bean;
13+
14+
@ConditionalOnMissingBean(type = "com.azure.spring.cloud.autoconfigure.implementation.servicebus.properties.AzureServiceBusConnectionDetails")
15+
@ConditionalOnProperty(value = "spring.cloud.azure.servicebus.enabled", havingValue = "true", matchIfMissing = true)
16+
@ConditionalOnAnyProperty(prefix = "spring.cloud.azure.servicebus", name = {"connection-string", "namespace"})
17+
class ConfigurationWithoutConnectionDetailsBean {
18+
19+
private final AzureGlobalProperties azureGlobalProperties;
20+
21+
ConfigurationWithoutConnectionDetailsBean(AzureGlobalProperties azureGlobalProperties) {
22+
this.azureGlobalProperties = azureGlobalProperties;
23+
}
24+
25+
@Bean
26+
@ConditionalOnMissingBean
27+
@ConfigurationProperties(AzureServiceBusProperties.PREFIX)
28+
AzureServiceBusProperties azureServiceBusProperties() {
29+
return AzureGlobalPropertiesUtils.loadProperties(azureGlobalProperties, new AzureServiceBusProperties());
30+
}
31+
32+
}

sdk/spring/spring-cloud-azure-autoconfigure/src/test/java/com/azure/spring/cloud/autoconfigure/implementation/servicebus/AzureServiceBusAutoConfigurationTests.java

Lines changed: 21 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
import com.azure.messaging.servicebus.models.ServiceBusReceiveMode;
99
import com.azure.spring.cloud.autoconfigure.implementation.AbstractAzureServiceConfigurationTests;
1010
import com.azure.spring.cloud.autoconfigure.implementation.context.properties.AzureGlobalProperties;
11+
import com.azure.spring.cloud.autoconfigure.implementation.servicebus.properties.AzureServiceBusConnectionDetails;
1112
import com.azure.spring.cloud.autoconfigure.implementation.servicebus.properties.AzureServiceBusProperties;
1213
import com.azure.spring.cloud.core.properties.profile.AzureEnvironmentProperties;
1314
import com.azure.spring.cloud.core.provider.AzureProfileOptionsProvider;
@@ -81,7 +82,7 @@ void configureAzureServiceBusPropertiesWithGlobalDefaults() {
8182
azureProperties.getCredential().setClientSecret("azure-client-secret");
8283
azureProperties.getRetry().getExponential().setBaseDelay(Duration.ofSeconds(2));
8384

84-
this.contextRunner
85+
this.getMinimalContextRunner()
8586
.withBean("azureProperties", AzureGlobalProperties.class, () -> azureProperties)
8687
.withPropertyValues(
8788
"spring.cloud.azure.servicebus.credential.client-id=servicebus-client-id",
@@ -104,7 +105,7 @@ void configureServiceBusDomainNameOverrideGlobalDefault() {
104105
AzureGlobalProperties azureProperties = new AzureGlobalProperties();
105106
azureProperties.getProfile().setCloudType(AzureProfileOptionsProvider.CloudType.AZURE_US_GOVERNMENT);
106107

107-
this.contextRunner
108+
this.getMinimalContextRunner()
108109
.withBean("azureProperties", AzureGlobalProperties.class, () -> azureProperties)
109110
.withPropertyValues(
110111
"spring.cloud.azure.servicebus.domain-name=servicebus.chinacloudapi.cn"
@@ -120,7 +121,7 @@ void configureServiceBusDomainNameOverrideGlobalDefault() {
120121

121122
@Test
122123
void configureAmqpTransportTypeShouldApply() {
123-
this.contextRunner
124+
this.getMinimalContextRunner()
124125
.withBean("azureProperties", AzureGlobalProperties.class, AzureGlobalProperties::new)
125126
.withPropertyValues("spring.cloud.azure.servicebus.client.transport-type=AmqpWebSockets")
126127
.run(context -> {
@@ -132,7 +133,7 @@ void configureAmqpTransportTypeShouldApply() {
132133

133134
@Test
134135
void configureRetryShouldApply() {
135-
this.contextRunner
136+
this.getMinimalContextRunner()
136137
.withBean("azureProperties", AzureGlobalProperties.class, AzureGlobalProperties::new)
137138
.withPropertyValues(
138139
"spring.cloud.azure.servicebus.retry.mode=fixed",
@@ -297,4 +298,20 @@ void consumerSubscriptionNameShouldConfigureConsumerClient() {
297298
assertThat(context).hasSingleBean(AzureServiceBusConsumerClientConfiguration.class);
298299
});
299300
}
301+
302+
@Test
303+
void connectionDetailsHasHigherPriority() {
304+
String connectionString = String.format(CONNECTION_STRING_FORMAT, "property-namespace");
305+
this.contextRunner
306+
.withPropertyValues(
307+
"spring.cloud.azure.servicebus.connection-string=" + connectionString
308+
)
309+
.withBean(AzureGlobalProperties.class, AzureGlobalProperties::new)
310+
.withBean(AzureServiceBusConnectionDetails.class, CustomAzureServiceBusConnectionDetails::new)
311+
.run(context -> {
312+
assertThat(context).hasSingleBean(AzureServiceBusProperties.class);
313+
AzureServiceBusProperties properties = context.getBean(AzureServiceBusProperties.class);
314+
assertEquals(CustomAzureServiceBusConnectionDetails.CONNECTION_STRING, properties.getConnectionString());
315+
});
316+
}
300317
}

0 commit comments

Comments
 (0)