From b68fb6effadce14ed4773761e683fe0b0202dc44 Mon Sep 17 00:00:00 2001 From: Rujun Chen Date: Tue, 30 Jun 2026 14:26:39 +0800 Subject: [PATCH 1/7] [Spring] Support custom ServiceBus JMS factory creation --- sdk/spring/CHANGELOG.md | 2 + .../jms/ServiceBusJmsAutoConfiguration.java | 27 ++++++ ...eBusJmsConnectionFactoryConfiguration.java | 28 +++++- ...ServiceBusJmsConnectionFactoryFactory.java | 43 +-------- ...ServiceBusJmsConnectionFactoryFactory.java | 20 ++++ ...msConnectionFactoryConfigurationTests.java | 91 +++++++++++++++++++ 6 files changed, 169 insertions(+), 42 deletions(-) create mode 100644 sdk/spring/spring-cloud-azure-autoconfigure/src/main/java/com/azure/spring/cloud/autoconfigure/jms/AzureServiceBusJmsConnectionFactoryFactory.java diff --git a/sdk/spring/CHANGELOG.md b/sdk/spring/CHANGELOG.md index 48f559bf9977..35431fd8cb48 100644 --- a/sdk/spring/CHANGELOG.md +++ b/sdk/spring/CHANGELOG.md @@ -8,6 +8,8 @@ This section includes changes in `spring-cloud-azure-autoconfigure` module. #### Features Added +- Added `AzureServiceBusJmsConnectionFactoryFactory` to allow applications to customize how `ServiceBusJmsConnectionFactory` instances are created, including support for custom subclasses. + #### Breaking Changes #### Bugs Fixed diff --git a/sdk/spring/spring-cloud-azure-autoconfigure/src/main/java/com/azure/spring/cloud/autoconfigure/implementation/jms/ServiceBusJmsAutoConfiguration.java b/sdk/spring/spring-cloud-azure-autoconfigure/src/main/java/com/azure/spring/cloud/autoconfigure/implementation/jms/ServiceBusJmsAutoConfiguration.java index 16dd582f6311..db1cdf3e921e 100644 --- a/sdk/spring/spring-cloud-azure-autoconfigure/src/main/java/com/azure/spring/cloud/autoconfigure/implementation/jms/ServiceBusJmsAutoConfiguration.java +++ b/sdk/spring/spring-cloud-azure-autoconfigure/src/main/java/com/azure/spring/cloud/autoconfigure/implementation/jms/ServiceBusJmsAutoConfiguration.java @@ -3,10 +3,15 @@ package com.azure.spring.cloud.autoconfigure.implementation.jms; +import com.azure.core.credential.TokenCredential; +import com.azure.identity.extensions.implementation.credential.TokenCredentialProviderOptions; +import com.azure.identity.extensions.implementation.credential.provider.TokenCredentialProvider; import com.azure.servicebus.jms.ServiceBusJmsConnectionFactory; +import com.azure.servicebus.jms.ServiceBusJmsConnectionFactorySettings; import com.azure.spring.cloud.autoconfigure.implementation.context.properties.AzureGlobalProperties; import com.azure.spring.cloud.autoconfigure.implementation.jms.properties.AzureServiceBusJmsProperties; import com.azure.spring.cloud.autoconfigure.implementation.resourcemanager.AzureServiceBusResourceManagerAutoConfiguration; +import com.azure.spring.cloud.autoconfigure.jms.AzureServiceBusJmsConnectionFactoryFactory; import com.azure.spring.cloud.autoconfigure.jms.AzureServiceBusJmsConnectionFactoryCustomizer; import com.azure.spring.cloud.core.implementation.util.AzurePasswordlessPropertiesUtils; import com.azure.spring.cloud.core.implementation.util.ReflectionUtils; @@ -19,6 +24,7 @@ import org.springframework.boot.autoconfigure.EnableAutoConfiguration; import org.springframework.boot.autoconfigure.condition.ConditionalOnClass; import org.springframework.boot.autoconfigure.condition.ConditionalOnExpression; +import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; import org.springframework.boot.jms.autoconfigure.JmsAutoConfiguration; import org.springframework.boot.jms.autoconfigure.JndiConnectionFactoryAutoConfiguration; @@ -31,8 +37,11 @@ import java.net.URI; import java.util.EnumMap; import java.util.Map; +import java.util.Properties; import java.util.function.BiFunction; +import static com.azure.spring.cloud.autoconfigure.implementation.util.SpringPasswordlessPropertiesUtils.enhancePasswordlessProperties; + /** * {@link EnableAutoConfiguration Auto-configuration} for Azure Service Bus JMS support. * @@ -59,6 +68,24 @@ AzureServiceBusJmsProperties serviceBusJmsProperties(AzureGlobalProperties azure return mergeAzureProperties(azureGlobalProperties, properties); } + @Bean + @ConditionalOnMissingBean + AzureServiceBusJmsConnectionFactoryFactory azureServiceBusJmsConnectionFactoryFactory(final AzureServiceBusJmsProperties properties) { + return () -> { + if (properties.isPasswordlessEnabled()) { + String hostName = + properties.getNamespace() + "." + properties.getProfile().getEnvironment().getServiceBusDomainName(); + Properties passwordlessProperties = properties.toPasswordlessProperties(); + enhancePasswordlessProperties(AzureServiceBusJmsProperties.PREFIX, properties, passwordlessProperties); + TokenCredentialProvider tokenCredentialProvider = TokenCredentialProvider.createDefault(new TokenCredentialProviderOptions(passwordlessProperties)); + TokenCredential tokenCredential = tokenCredentialProvider.get(); + return new ServiceBusJmsConnectionFactory(tokenCredential, hostName, new ServiceBusJmsConnectionFactorySettings()); + } else { + return new ServiceBusJmsConnectionFactory(properties.getConnectionString(), new ServiceBusJmsConnectionFactorySettings()); + } + }; + } + /** * Standard tier does not support the property "com.microsoft:is-client-provider", so remove it. */ diff --git a/sdk/spring/spring-cloud-azure-autoconfigure/src/main/java/com/azure/spring/cloud/autoconfigure/implementation/jms/ServiceBusJmsConnectionFactoryConfiguration.java b/sdk/spring/spring-cloud-azure-autoconfigure/src/main/java/com/azure/spring/cloud/autoconfigure/implementation/jms/ServiceBusJmsConnectionFactoryConfiguration.java index 67cc5a455358..98718fc21877 100644 --- a/sdk/spring/spring-cloud-azure-autoconfigure/src/main/java/com/azure/spring/cloud/autoconfigure/implementation/jms/ServiceBusJmsConnectionFactoryConfiguration.java +++ b/sdk/spring/spring-cloud-azure-autoconfigure/src/main/java/com/azure/spring/cloud/autoconfigure/implementation/jms/ServiceBusJmsConnectionFactoryConfiguration.java @@ -3,9 +3,14 @@ package com.azure.spring.cloud.autoconfigure.implementation.jms; +import com.azure.core.credential.TokenCredential; +import com.azure.identity.extensions.implementation.credential.TokenCredentialProviderOptions; +import com.azure.identity.extensions.implementation.credential.provider.TokenCredentialProvider; import com.azure.servicebus.jms.ServiceBusJmsConnectionFactory; +import com.azure.servicebus.jms.ServiceBusJmsConnectionFactorySettings; import com.azure.spring.cloud.autoconfigure.implementation.jms.properties.AzureServiceBusJmsProperties; import com.azure.spring.cloud.autoconfigure.jms.AzureServiceBusJmsConnectionFactoryCustomizer; +import com.azure.spring.cloud.autoconfigure.jms.AzureServiceBusJmsConnectionFactoryFactory; import jakarta.jms.ConnectionFactory; import org.messaginghub.pooled.jms.JmsPoolConnectionFactory; import org.springframework.beans.BeansException; @@ -26,8 +31,10 @@ import org.springframework.jms.connection.CachingConnectionFactory; import org.springframework.util.ClassUtils; +import java.util.Properties; import java.util.stream.Collectors; +import static com.azure.spring.cloud.autoconfigure.implementation.util.SpringPasswordlessPropertiesUtils.enhancePasswordlessProperties; import static org.springframework.beans.factory.support.BeanDefinitionBuilder.genericBeanDefinition; /** @@ -56,7 +63,19 @@ static ServiceBusJmsConnectionFactory createServiceBusJmsConnectionFactory( AzureServiceBusJmsProperties properties, java.util.List customizers) { return new ServiceBusJmsConnectionFactoryFactory(properties, customizers) - .createConnectionFactory(ServiceBusJmsConnectionFactory.class); + .createConnectionFactory(() -> { + if (properties.isPasswordlessEnabled()) { + String hostName = + properties.getNamespace() + "." + properties.getProfile().getEnvironment().getServiceBusDomainName(); + Properties passwordlessProperties = properties.toPasswordlessProperties(); + enhancePasswordlessProperties(AzureServiceBusJmsProperties.PREFIX, properties, passwordlessProperties); + TokenCredentialProvider tokenCredentialProvider = TokenCredentialProvider.createDefault(new TokenCredentialProviderOptions(passwordlessProperties)); + TokenCredential tokenCredential = tokenCredentialProvider.get(); + return new ServiceBusJmsConnectionFactory(tokenCredential, hostName, new ServiceBusJmsConnectionFactorySettings()); + } else { + return new ServiceBusJmsConnectionFactory(properties.getConnectionString(), new ServiceBusJmsConnectionFactorySettings()); + } + }); } /** @@ -195,10 +214,11 @@ private void registerJmsPoolConnectionFactory(BeanDefinitionRegistry registry) { private ServiceBusJmsConnectionFactory createServiceBusJmsConnectionFactory() { AzureServiceBusJmsProperties serviceBusJmsProperties = beanFactory.getBean(AzureServiceBusJmsProperties.class); + AzureServiceBusJmsConnectionFactoryFactory instanceFactory = beanFactory.getBean(AzureServiceBusJmsConnectionFactoryFactory.class); ObjectProvider factoryCustomizers = beanFactory.getBeanProvider(AzureServiceBusJmsConnectionFactoryCustomizer.class); - return ServiceBusJmsConnectionFactoryConfiguration.createServiceBusJmsConnectionFactory( - serviceBusJmsProperties, - factoryCustomizers.orderedStream().collect(Collectors.toList())); + return new ServiceBusJmsConnectionFactoryFactory(serviceBusJmsProperties, + factoryCustomizers.orderedStream().collect(Collectors.toList())) + .createConnectionFactory(instanceFactory); } } } diff --git a/sdk/spring/spring-cloud-azure-autoconfigure/src/main/java/com/azure/spring/cloud/autoconfigure/implementation/jms/ServiceBusJmsConnectionFactoryFactory.java b/sdk/spring/spring-cloud-azure-autoconfigure/src/main/java/com/azure/spring/cloud/autoconfigure/implementation/jms/ServiceBusJmsConnectionFactoryFactory.java index b974a55f4c07..6e216fb0fcf6 100644 --- a/sdk/spring/spring-cloud-azure-autoconfigure/src/main/java/com/azure/spring/cloud/autoconfigure/implementation/jms/ServiceBusJmsConnectionFactoryFactory.java +++ b/sdk/spring/spring-cloud-azure-autoconfigure/src/main/java/com/azure/spring/cloud/autoconfigure/implementation/jms/ServiceBusJmsConnectionFactoryFactory.java @@ -3,44 +3,29 @@ package com.azure.spring.cloud.autoconfigure.implementation.jms; -import com.azure.core.credential.TokenCredential; -import com.azure.identity.extensions.implementation.credential.TokenCredentialProviderOptions; -import com.azure.identity.extensions.implementation.credential.provider.TokenCredentialProvider; import com.azure.servicebus.jms.ServiceBusJmsConnectionFactory; -import com.azure.servicebus.jms.ServiceBusJmsConnectionFactorySettings; import com.azure.spring.cloud.autoconfigure.implementation.jms.properties.AzureServiceBusJmsProperties; import com.azure.spring.cloud.autoconfigure.jms.AzureServiceBusJmsConnectionFactoryCustomizer; +import com.azure.spring.cloud.autoconfigure.jms.AzureServiceBusJmsConnectionFactoryFactory; import org.springframework.util.Assert; import org.springframework.util.StringUtils; -import java.lang.reflect.InvocationTargetException; import java.util.Collections; import java.util.List; -import java.util.Properties; - -import static com.azure.spring.cloud.autoconfigure.implementation.util.SpringPasswordlessPropertiesUtils.enhancePasswordlessProperties; class ServiceBusJmsConnectionFactoryFactory { private final AzureServiceBusJmsProperties properties; private final List factoryCustomizers; - private final TokenCredentialProvider tokenCredentialProvider; ServiceBusJmsConnectionFactoryFactory(AzureServiceBusJmsProperties properties, List factoryCustomizers) { Assert.notNull(properties, "Properties must not be null"); this.properties = properties; this.factoryCustomizers = (factoryCustomizers != null) ? factoryCustomizers : Collections.emptyList(); - if (properties.isPasswordlessEnabled()) { - Properties passwordlessProperties = properties.toPasswordlessProperties(); - enhancePasswordlessProperties(AzureServiceBusJmsProperties.PREFIX, properties, passwordlessProperties); - this.tokenCredentialProvider = TokenCredentialProvider.createDefault(new TokenCredentialProviderOptions(passwordlessProperties)); - } else { - this.tokenCredentialProvider = null; - } } - T createConnectionFactory(Class factoryClass) { - T factory = createConnectionFactoryInstance(factoryClass); + ServiceBusJmsConnectionFactory createConnectionFactory(AzureServiceBusJmsConnectionFactoryFactory instanceFactory) { + ServiceBusJmsConnectionFactory factory = createConnectionFactoryInstance(instanceFactory); setClientId(factory); setPrefetchPolicy(factory); customize(factory); @@ -65,26 +50,8 @@ private void setPrefetchPolicy(T fact String.valueOf(prefetchProperties.getTopicPrefetch())); } - private T createConnectionFactoryInstance(Class factoryClass) { - try { - T factory; - if (properties.isPasswordlessEnabled()) { - String hostName = - properties.getNamespace() + "." + properties.getProfile().getEnvironment().getServiceBusDomainName(); - TokenCredential tokenCredential = tokenCredentialProvider.get(); - factory = factoryClass.getConstructor(TokenCredential.class, String.class, - ServiceBusJmsConnectionFactorySettings.class) - .newInstance(tokenCredential, hostName, - new ServiceBusJmsConnectionFactorySettings()); - } else { - factory = factoryClass.getConstructor(String.class, ServiceBusJmsConnectionFactorySettings.class) - .newInstance(properties.getConnectionString(), - new ServiceBusJmsConnectionFactorySettings()); - } - return factory; - } catch (NoSuchMethodException | SecurityException | InstantiationException | IllegalAccessException | IllegalArgumentException | InvocationTargetException ex) { - throw new IllegalStateException("Unable to create JmsConnectionFactory", ex); - } + private ServiceBusJmsConnectionFactory createConnectionFactoryInstance(AzureServiceBusJmsConnectionFactoryFactory instanceFactory) { + return instanceFactory.createServiceBusJmsConnectionFactory(); } private void customize(ServiceBusJmsConnectionFactory connectionFactory) { diff --git a/sdk/spring/spring-cloud-azure-autoconfigure/src/main/java/com/azure/spring/cloud/autoconfigure/jms/AzureServiceBusJmsConnectionFactoryFactory.java b/sdk/spring/spring-cloud-azure-autoconfigure/src/main/java/com/azure/spring/cloud/autoconfigure/jms/AzureServiceBusJmsConnectionFactoryFactory.java new file mode 100644 index 000000000000..cae5f531db02 --- /dev/null +++ b/sdk/spring/spring-cloud-azure-autoconfigure/src/main/java/com/azure/spring/cloud/autoconfigure/jms/AzureServiceBusJmsConnectionFactoryFactory.java @@ -0,0 +1,20 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +package com.azure.spring.cloud.autoconfigure.jms; + +import com.azure.servicebus.jms.ServiceBusJmsConnectionFactory; + +/** + * The interface used to define how the {@link ServiceBusJmsConnectionFactory} instance is created. + */ +@FunctionalInterface +public interface AzureServiceBusJmsConnectionFactoryFactory { + + /** + * Creates an instance of {@link ServiceBusJmsConnectionFactory} or a subclass thereof. + * + * @return an instance of {@link ServiceBusJmsConnectionFactory} + */ + ServiceBusJmsConnectionFactory createServiceBusJmsConnectionFactory(); +} diff --git a/sdk/spring/spring-cloud-azure-autoconfigure/src/test/java/com/azure/spring/cloud/autoconfigure/implementation/jms/ServiceBusJmsConnectionFactoryConfigurationTests.java b/sdk/spring/spring-cloud-azure-autoconfigure/src/test/java/com/azure/spring/cloud/autoconfigure/implementation/jms/ServiceBusJmsConnectionFactoryConfigurationTests.java index b31906dba3f7..b67013178bdb 100644 --- a/sdk/spring/spring-cloud-azure-autoconfigure/src/test/java/com/azure/spring/cloud/autoconfigure/implementation/jms/ServiceBusJmsConnectionFactoryConfigurationTests.java +++ b/sdk/spring/spring-cloud-azure-autoconfigure/src/test/java/com/azure/spring/cloud/autoconfigure/implementation/jms/ServiceBusJmsConnectionFactoryConfigurationTests.java @@ -3,8 +3,11 @@ package com.azure.spring.cloud.autoconfigure.implementation.jms; +import com.azure.core.credential.TokenCredential; import com.azure.servicebus.jms.ServiceBusJmsConnectionFactory; +import com.azure.servicebus.jms.ServiceBusJmsConnectionFactorySettings; import com.azure.spring.cloud.autoconfigure.implementation.context.properties.AzureGlobalProperties; +import com.azure.spring.cloud.autoconfigure.jms.AzureServiceBusJmsConnectionFactoryFactory; import jakarta.jms.Connection; import jakarta.jms.ConnectionFactory; import jakarta.jms.Destination; @@ -19,6 +22,7 @@ import org.springframework.boot.jms.autoconfigure.JmsAutoConfiguration; import org.springframework.boot.test.context.FilteredClassLoader; import org.springframework.boot.test.context.runner.ApplicationContextRunner; +import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.PropertySource; import org.springframework.jms.connection.CachingConnectionFactory; @@ -180,6 +184,72 @@ void fallbackToServiceBusConnectionFactoryWhenNoCachingOrPoolClassesPresent(Stri }); } + @Test + void useCustomServiceBusJmsConnectionFactoryClassForServiceBusFactory() { + this.contextRunner + .withUserConfiguration(CustomConnectionFactoryClassConfiguration.class) + .withPropertyValues( + "spring.jms.servicebus.pricing-tier=premium", + "spring.jms.servicebus.pool.enabled=false", + "spring.jms.cache.enabled=false" + ) + .run(context -> { + assertThat(context).hasSingleBean(ServiceBusJmsConnectionFactory.class); + assertThat(context.getBean(ServiceBusJmsConnectionFactory.class)) + .isInstanceOf(CustomServiceBusJmsConnectionFactory.class); + }); + } + + @Test + void useCustomServiceBusJmsConnectionFactoryClassForPasswordlessServiceBusFactory() { + this.contextRunner + .withUserConfiguration(CustomConnectionFactoryClassConfiguration.class) + .withPropertyValues( + "spring.jms.servicebus.pricing-tier=premium", + "spring.jms.servicebus.passwordless-enabled=true", + "spring.jms.servicebus.namespace=test-namespace", + "spring.jms.servicebus.pool.enabled=false", + "spring.jms.cache.enabled=false" + ) + .run(context -> { + assertThat(context).hasSingleBean(ServiceBusJmsConnectionFactory.class); + assertThat(context.getBean(ServiceBusJmsConnectionFactory.class)) + .isInstanceOf(CustomServiceBusJmsConnectionFactory.class); + }); + } + + @Test + void useCustomServiceBusJmsConnectionFactoryClassForCachingFactory() { + this.contextRunner + .withUserConfiguration(CustomConnectionFactoryClassConfiguration.class) + .withPropertyValues( + "spring.jms.servicebus.pricing-tier=premium", + "spring.jms.cache.enabled=true" + ) + .run(context -> { + assertThat(context).hasSingleBean(CachingConnectionFactory.class); + CachingConnectionFactory cachingConnectionFactory = context.getBean(CachingConnectionFactory.class); + assertThat(cachingConnectionFactory.getTargetConnectionFactory()) + .isInstanceOf(CustomServiceBusJmsConnectionFactory.class); + }); + } + + @Test + void useCustomServiceBusJmsConnectionFactoryClassForPoolingFactory() { + this.contextRunner + .withUserConfiguration(CustomConnectionFactoryClassConfiguration.class) + .withPropertyValues( + "spring.jms.servicebus.pricing-tier=premium", + "spring.jms.servicebus.pool.enabled=true" + ) + .run(context -> { + assertThat(context).hasSingleBean(JmsPoolConnectionFactory.class); + JmsPoolConnectionFactory poolConnectionFactory = context.getBean(JmsPoolConnectionFactory.class); + assertThat(poolConnectionFactory.getConnectionFactory()) + .isInstanceOf(CustomServiceBusJmsConnectionFactory.class); + }); + } + @Test void cachingConnectionFactoryReusesSameProducerForSameDestination() throws Exception { // Create mock objects for JMS components @@ -276,4 +346,25 @@ private Session createServiceBusJmsSession(Session innerSession) throws Exceptio static class AdditionalPropertySourceConfiguration { } + + @Configuration + static class CustomConnectionFactoryClassConfiguration { + @Bean + AzureServiceBusJmsConnectionFactoryFactory connectionFactoryFactory() { + return () -> new CustomServiceBusJmsConnectionFactory( + String.format(CONNECTION_STRING_FORMAT, "test-namespace"), + new ServiceBusJmsConnectionFactorySettings()); + } + } + + static class CustomServiceBusJmsConnectionFactory extends ServiceBusJmsConnectionFactory { + public CustomServiceBusJmsConnectionFactory(String connectionString, ServiceBusJmsConnectionFactorySettings settings) { + super(connectionString, settings); + } + + public CustomServiceBusJmsConnectionFactory(TokenCredential tokenCredential, String host, + ServiceBusJmsConnectionFactorySettings settings) { + super(tokenCredential, host, settings); + } + } } From e79522c92809d0799c506b87220238be1bca11ed Mon Sep 17 00:00:00 2001 From: Rujun Chen Date: Tue, 30 Jun 2026 14:32:25 +0800 Subject: [PATCH 2/7] [Spring] Add PR reference for JMS factory changelog entry --- sdk/spring/CHANGELOG.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sdk/spring/CHANGELOG.md b/sdk/spring/CHANGELOG.md index 35431fd8cb48..b88f5808ae61 100644 --- a/sdk/spring/CHANGELOG.md +++ b/sdk/spring/CHANGELOG.md @@ -8,7 +8,7 @@ This section includes changes in `spring-cloud-azure-autoconfigure` module. #### Features Added -- Added `AzureServiceBusJmsConnectionFactoryFactory` to allow applications to customize how `ServiceBusJmsConnectionFactory` instances are created, including support for custom subclasses. +- Added `AzureServiceBusJmsConnectionFactoryFactory` to allow applications to customize how `ServiceBusJmsConnectionFactory` instances are created, including support for custom subclasses ([#49676](https://github.com/Azure/azure-sdk-for-java/pull/49676)). #### Breaking Changes From 4645bc8e68734a5b819752d91c76f4e8267afcf6 Mon Sep 17 00:00:00 2001 From: Rujun Chen Date: Tue, 30 Jun 2026 14:37:29 +0800 Subject: [PATCH 3/7] [Spring] Address PR review comments for JMS factory hook --- .../jms/ServiceBusJmsAutoConfiguration.java | 15 +++++++--- ...eBusJmsConnectionFactoryConfiguration.java | 30 +++++-------------- ...ServiceBusJmsConnectionFactoryFactory.java | 2 ++ .../ServiceBusJmsContainerConfiguration.java | 7 ++++- ...msConnectionFactoryConfigurationTests.java | 6 ++-- 5 files changed, 30 insertions(+), 30 deletions(-) diff --git a/sdk/spring/spring-cloud-azure-autoconfigure/src/main/java/com/azure/spring/cloud/autoconfigure/implementation/jms/ServiceBusJmsAutoConfiguration.java b/sdk/spring/spring-cloud-azure-autoconfigure/src/main/java/com/azure/spring/cloud/autoconfigure/implementation/jms/ServiceBusJmsAutoConfiguration.java index db1cdf3e921e..3571152e215b 100644 --- a/sdk/spring/spring-cloud-azure-autoconfigure/src/main/java/com/azure/spring/cloud/autoconfigure/implementation/jms/ServiceBusJmsAutoConfiguration.java +++ b/sdk/spring/spring-cloud-azure-autoconfigure/src/main/java/com/azure/spring/cloud/autoconfigure/implementation/jms/ServiceBusJmsAutoConfiguration.java @@ -70,18 +70,25 @@ AzureServiceBusJmsProperties serviceBusJmsProperties(AzureGlobalProperties azure @Bean @ConditionalOnMissingBean - AzureServiceBusJmsConnectionFactoryFactory azureServiceBusJmsConnectionFactoryFactory(final AzureServiceBusJmsProperties properties) { + AzureServiceBusJmsConnectionFactoryFactory azureServiceBusJmsConnectionFactoryFactory( + final AzureServiceBusJmsProperties properties) { return () -> { if (properties.isPasswordlessEnabled()) { String hostName = properties.getNamespace() + "." + properties.getProfile().getEnvironment().getServiceBusDomainName(); Properties passwordlessProperties = properties.toPasswordlessProperties(); enhancePasswordlessProperties(AzureServiceBusJmsProperties.PREFIX, properties, passwordlessProperties); - TokenCredentialProvider tokenCredentialProvider = TokenCredentialProvider.createDefault(new TokenCredentialProviderOptions(passwordlessProperties)); + TokenCredentialProvider tokenCredentialProvider = TokenCredentialProvider.createDefault( + new TokenCredentialProviderOptions(passwordlessProperties)); TokenCredential tokenCredential = tokenCredentialProvider.get(); - return new ServiceBusJmsConnectionFactory(tokenCredential, hostName, new ServiceBusJmsConnectionFactorySettings()); + return new ServiceBusJmsConnectionFactory( + tokenCredential, + hostName, + new ServiceBusJmsConnectionFactorySettings()); } else { - return new ServiceBusJmsConnectionFactory(properties.getConnectionString(), new ServiceBusJmsConnectionFactorySettings()); + return new ServiceBusJmsConnectionFactory( + properties.getConnectionString(), + new ServiceBusJmsConnectionFactorySettings()); } }; } diff --git a/sdk/spring/spring-cloud-azure-autoconfigure/src/main/java/com/azure/spring/cloud/autoconfigure/implementation/jms/ServiceBusJmsConnectionFactoryConfiguration.java b/sdk/spring/spring-cloud-azure-autoconfigure/src/main/java/com/azure/spring/cloud/autoconfigure/implementation/jms/ServiceBusJmsConnectionFactoryConfiguration.java index 98718fc21877..c5c3fbaa2df6 100644 --- a/sdk/spring/spring-cloud-azure-autoconfigure/src/main/java/com/azure/spring/cloud/autoconfigure/implementation/jms/ServiceBusJmsConnectionFactoryConfiguration.java +++ b/sdk/spring/spring-cloud-azure-autoconfigure/src/main/java/com/azure/spring/cloud/autoconfigure/implementation/jms/ServiceBusJmsConnectionFactoryConfiguration.java @@ -3,11 +3,7 @@ package com.azure.spring.cloud.autoconfigure.implementation.jms; -import com.azure.core.credential.TokenCredential; -import com.azure.identity.extensions.implementation.credential.TokenCredentialProviderOptions; -import com.azure.identity.extensions.implementation.credential.provider.TokenCredentialProvider; import com.azure.servicebus.jms.ServiceBusJmsConnectionFactory; -import com.azure.servicebus.jms.ServiceBusJmsConnectionFactorySettings; import com.azure.spring.cloud.autoconfigure.implementation.jms.properties.AzureServiceBusJmsProperties; import com.azure.spring.cloud.autoconfigure.jms.AzureServiceBusJmsConnectionFactoryCustomizer; import com.azure.spring.cloud.autoconfigure.jms.AzureServiceBusJmsConnectionFactoryFactory; @@ -31,10 +27,8 @@ import org.springframework.jms.connection.CachingConnectionFactory; import org.springframework.util.ClassUtils; -import java.util.Properties; import java.util.stream.Collectors; -import static com.azure.spring.cloud.autoconfigure.implementation.util.SpringPasswordlessPropertiesUtils.enhancePasswordlessProperties; import static org.springframework.beans.factory.support.BeanDefinitionBuilder.genericBeanDefinition; /** @@ -61,21 +55,10 @@ class ServiceBusJmsConnectionFactoryConfiguration { */ static ServiceBusJmsConnectionFactory createServiceBusJmsConnectionFactory( AzureServiceBusJmsProperties properties, - java.util.List customizers) { + java.util.List customizers, + AzureServiceBusJmsConnectionFactoryFactory instanceFactory) { return new ServiceBusJmsConnectionFactoryFactory(properties, customizers) - .createConnectionFactory(() -> { - if (properties.isPasswordlessEnabled()) { - String hostName = - properties.getNamespace() + "." + properties.getProfile().getEnvironment().getServiceBusDomainName(); - Properties passwordlessProperties = properties.toPasswordlessProperties(); - enhancePasswordlessProperties(AzureServiceBusJmsProperties.PREFIX, properties, passwordlessProperties); - TokenCredentialProvider tokenCredentialProvider = TokenCredentialProvider.createDefault(new TokenCredentialProviderOptions(passwordlessProperties)); - TokenCredential tokenCredential = tokenCredentialProvider.get(); - return new ServiceBusJmsConnectionFactory(tokenCredential, hostName, new ServiceBusJmsConnectionFactorySettings()); - } else { - return new ServiceBusJmsConnectionFactory(properties.getConnectionString(), new ServiceBusJmsConnectionFactorySettings()); - } - }); + .createConnectionFactory(instanceFactory); } /** @@ -216,9 +199,10 @@ private ServiceBusJmsConnectionFactory createServiceBusJmsConnectionFactory() { AzureServiceBusJmsProperties serviceBusJmsProperties = beanFactory.getBean(AzureServiceBusJmsProperties.class); AzureServiceBusJmsConnectionFactoryFactory instanceFactory = beanFactory.getBean(AzureServiceBusJmsConnectionFactoryFactory.class); ObjectProvider factoryCustomizers = beanFactory.getBeanProvider(AzureServiceBusJmsConnectionFactoryCustomizer.class); - return new ServiceBusJmsConnectionFactoryFactory(serviceBusJmsProperties, - factoryCustomizers.orderedStream().collect(Collectors.toList())) - .createConnectionFactory(instanceFactory); + return ServiceBusJmsConnectionFactoryConfiguration.createServiceBusJmsConnectionFactory( + serviceBusJmsProperties, + factoryCustomizers.orderedStream().collect(Collectors.toList()), + instanceFactory); } } } diff --git a/sdk/spring/spring-cloud-azure-autoconfigure/src/main/java/com/azure/spring/cloud/autoconfigure/implementation/jms/ServiceBusJmsConnectionFactoryFactory.java b/sdk/spring/spring-cloud-azure-autoconfigure/src/main/java/com/azure/spring/cloud/autoconfigure/implementation/jms/ServiceBusJmsConnectionFactoryFactory.java index 6e216fb0fcf6..9dabcdee1e9d 100644 --- a/sdk/spring/spring-cloud-azure-autoconfigure/src/main/java/com/azure/spring/cloud/autoconfigure/implementation/jms/ServiceBusJmsConnectionFactoryFactory.java +++ b/sdk/spring/spring-cloud-azure-autoconfigure/src/main/java/com/azure/spring/cloud/autoconfigure/implementation/jms/ServiceBusJmsConnectionFactoryFactory.java @@ -25,7 +25,9 @@ class ServiceBusJmsConnectionFactoryFactory { } ServiceBusJmsConnectionFactory createConnectionFactory(AzureServiceBusJmsConnectionFactoryFactory instanceFactory) { + Assert.notNull(instanceFactory, "AzureServiceBusJmsConnectionFactoryFactory must not be null"); ServiceBusJmsConnectionFactory factory = createConnectionFactoryInstance(instanceFactory); + Assert.notNull(factory, "AzureServiceBusJmsConnectionFactoryFactory must create a non-null ServiceBusJmsConnectionFactory"); setClientId(factory); setPrefetchPolicy(factory); customize(factory); diff --git a/sdk/spring/spring-cloud-azure-autoconfigure/src/main/java/com/azure/spring/cloud/autoconfigure/implementation/jms/ServiceBusJmsContainerConfiguration.java b/sdk/spring/spring-cloud-azure-autoconfigure/src/main/java/com/azure/spring/cloud/autoconfigure/implementation/jms/ServiceBusJmsContainerConfiguration.java index b487df39a202..8fd5d3bcb8d3 100644 --- a/sdk/spring/spring-cloud-azure-autoconfigure/src/main/java/com/azure/spring/cloud/autoconfigure/implementation/jms/ServiceBusJmsContainerConfiguration.java +++ b/sdk/spring/spring-cloud-azure-autoconfigure/src/main/java/com/azure/spring/cloud/autoconfigure/implementation/jms/ServiceBusJmsContainerConfiguration.java @@ -6,6 +6,7 @@ import com.azure.servicebus.jms.ServiceBusJmsConnectionFactory; import com.azure.spring.cloud.autoconfigure.implementation.jms.properties.AzureServiceBusJmsProperties; import com.azure.spring.cloud.autoconfigure.jms.AzureServiceBusJmsConnectionFactoryCustomizer; +import com.azure.spring.cloud.autoconfigure.jms.AzureServiceBusJmsConnectionFactoryFactory; import jakarta.jms.ConnectionFactory; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -68,6 +69,7 @@ class ServiceBusJmsContainerConfiguration implements DisposableBean { private final AzureServiceBusJmsProperties azureServiceBusJMSProperties; private final ObjectProvider factoryCustomizers; + private final AzureServiceBusJmsConnectionFactoryFactory instanceFactory; private final Environment environment; private final JmsProperties jmsProperties; @@ -79,10 +81,12 @@ class ServiceBusJmsContainerConfiguration implements DisposableBean { ServiceBusJmsContainerConfiguration(AzureServiceBusJmsProperties azureServiceBusJMSProperties, ObjectProvider factoryCustomizers, + AzureServiceBusJmsConnectionFactoryFactory instanceFactory, Environment environment, JmsProperties jmsProperties) { this.azureServiceBusJMSProperties = azureServiceBusJMSProperties; this.factoryCustomizers = factoryCustomizers; + this.instanceFactory = instanceFactory; this.environment = environment; this.jmsProperties = jmsProperties; } @@ -199,7 +203,8 @@ private synchronized ServiceBusJmsConnectionFactory getOrCreateDedicatedServiceB private ServiceBusJmsConnectionFactory createServiceBusJmsConnectionFactory() { return ServiceBusJmsConnectionFactoryConfiguration.createServiceBusJmsConnectionFactory( azureServiceBusJMSProperties, - factoryCustomizers.orderedStream().collect(Collectors.toList())); + factoryCustomizers.orderedStream().collect(Collectors.toList()), + instanceFactory); } private void configureCommonListenerContainerFactory(DefaultJmsListenerContainerFactory jmsListenerContainerFactory) { diff --git a/sdk/spring/spring-cloud-azure-autoconfigure/src/test/java/com/azure/spring/cloud/autoconfigure/implementation/jms/ServiceBusJmsConnectionFactoryConfigurationTests.java b/sdk/spring/spring-cloud-azure-autoconfigure/src/test/java/com/azure/spring/cloud/autoconfigure/implementation/jms/ServiceBusJmsConnectionFactoryConfigurationTests.java index b67013178bdb..7c5394807d25 100644 --- a/sdk/spring/spring-cloud-azure-autoconfigure/src/test/java/com/azure/spring/cloud/autoconfigure/implementation/jms/ServiceBusJmsConnectionFactoryConfigurationTests.java +++ b/sdk/spring/spring-cloud-azure-autoconfigure/src/test/java/com/azure/spring/cloud/autoconfigure/implementation/jms/ServiceBusJmsConnectionFactoryConfigurationTests.java @@ -358,11 +358,13 @@ AzureServiceBusJmsConnectionFactoryFactory connectionFactoryFactory() { } static class CustomServiceBusJmsConnectionFactory extends ServiceBusJmsConnectionFactory { - public CustomServiceBusJmsConnectionFactory(String connectionString, ServiceBusJmsConnectionFactorySettings settings) { + CustomServiceBusJmsConnectionFactory( + String connectionString, + ServiceBusJmsConnectionFactorySettings settings) { super(connectionString, settings); } - public CustomServiceBusJmsConnectionFactory(TokenCredential tokenCredential, String host, + CustomServiceBusJmsConnectionFactory(TokenCredential tokenCredential, String host, ServiceBusJmsConnectionFactorySettings settings) { super(tokenCredential, host, settings); } From 70c3ae98064e488223ea4b447b8cff53d022665e Mon Sep 17 00:00:00 2001 From: Rujun Chen Date: Tue, 30 Jun 2026 14:48:25 +0800 Subject: [PATCH 4/7] [Spring] Polish docs and formatting from review --- .../implementation/jms/ServiceBusJmsAutoConfiguration.java | 4 +++- .../jms/ServiceBusJmsConnectionFactoryConfiguration.java | 1 + .../jms/ServiceBusJmsConnectionFactoryFactory.java | 4 +++- 3 files changed, 7 insertions(+), 2 deletions(-) diff --git a/sdk/spring/spring-cloud-azure-autoconfigure/src/main/java/com/azure/spring/cloud/autoconfigure/implementation/jms/ServiceBusJmsAutoConfiguration.java b/sdk/spring/spring-cloud-azure-autoconfigure/src/main/java/com/azure/spring/cloud/autoconfigure/implementation/jms/ServiceBusJmsAutoConfiguration.java index 3571152e215b..4ec523784919 100644 --- a/sdk/spring/spring-cloud-azure-autoconfigure/src/main/java/com/azure/spring/cloud/autoconfigure/implementation/jms/ServiceBusJmsAutoConfiguration.java +++ b/sdk/spring/spring-cloud-azure-autoconfigure/src/main/java/com/azure/spring/cloud/autoconfigure/implementation/jms/ServiceBusJmsAutoConfiguration.java @@ -75,7 +75,9 @@ AzureServiceBusJmsConnectionFactoryFactory azureServiceBusJmsConnectionFactoryFa return () -> { if (properties.isPasswordlessEnabled()) { String hostName = - properties.getNamespace() + "." + properties.getProfile().getEnvironment().getServiceBusDomainName(); + properties.getNamespace() + + "." + + properties.getProfile().getEnvironment().getServiceBusDomainName(); Properties passwordlessProperties = properties.toPasswordlessProperties(); enhancePasswordlessProperties(AzureServiceBusJmsProperties.PREFIX, properties, passwordlessProperties); TokenCredentialProvider tokenCredentialProvider = TokenCredentialProvider.createDefault( diff --git a/sdk/spring/spring-cloud-azure-autoconfigure/src/main/java/com/azure/spring/cloud/autoconfigure/implementation/jms/ServiceBusJmsConnectionFactoryConfiguration.java b/sdk/spring/spring-cloud-azure-autoconfigure/src/main/java/com/azure/spring/cloud/autoconfigure/implementation/jms/ServiceBusJmsConnectionFactoryConfiguration.java index c5c3fbaa2df6..668409368e5a 100644 --- a/sdk/spring/spring-cloud-azure-autoconfigure/src/main/java/com/azure/spring/cloud/autoconfigure/implementation/jms/ServiceBusJmsConnectionFactoryConfiguration.java +++ b/sdk/spring/spring-cloud-azure-autoconfigure/src/main/java/com/azure/spring/cloud/autoconfigure/implementation/jms/ServiceBusJmsConnectionFactoryConfiguration.java @@ -51,6 +51,7 @@ class ServiceBusJmsConnectionFactoryConfiguration { * * @param properties the Azure Service Bus JMS properties * @param customizers the list of customizers to apply + * @param instanceFactory the factory used to create the ServiceBusJmsConnectionFactory instance * @return a configured ServiceBusJmsConnectionFactory instance */ static ServiceBusJmsConnectionFactory createServiceBusJmsConnectionFactory( diff --git a/sdk/spring/spring-cloud-azure-autoconfigure/src/main/java/com/azure/spring/cloud/autoconfigure/implementation/jms/ServiceBusJmsConnectionFactoryFactory.java b/sdk/spring/spring-cloud-azure-autoconfigure/src/main/java/com/azure/spring/cloud/autoconfigure/implementation/jms/ServiceBusJmsConnectionFactoryFactory.java index 9dabcdee1e9d..e5f060bf11d8 100644 --- a/sdk/spring/spring-cloud-azure-autoconfigure/src/main/java/com/azure/spring/cloud/autoconfigure/implementation/jms/ServiceBusJmsConnectionFactoryFactory.java +++ b/sdk/spring/spring-cloud-azure-autoconfigure/src/main/java/com/azure/spring/cloud/autoconfigure/implementation/jms/ServiceBusJmsConnectionFactoryFactory.java @@ -27,7 +27,9 @@ class ServiceBusJmsConnectionFactoryFactory { ServiceBusJmsConnectionFactory createConnectionFactory(AzureServiceBusJmsConnectionFactoryFactory instanceFactory) { Assert.notNull(instanceFactory, "AzureServiceBusJmsConnectionFactoryFactory must not be null"); ServiceBusJmsConnectionFactory factory = createConnectionFactoryInstance(instanceFactory); - Assert.notNull(factory, "AzureServiceBusJmsConnectionFactoryFactory must create a non-null ServiceBusJmsConnectionFactory"); + Assert.notNull( + factory, + "AzureServiceBusJmsConnectionFactoryFactory must create a non-null ServiceBusJmsConnectionFactory"); setClientId(factory); setPrefetchPolicy(factory); customize(factory); From 80f784b2b342eeca8e885afcae3c6b3dafd0ab68 Mon Sep 17 00:00:00 2001 From: Rujun Chen Date: Tue, 30 Jun 2026 14:57:00 +0800 Subject: [PATCH 5/7] [Spring] Address latest PR review comments --- .../jms/ServiceBusJmsAutoConfiguration.java | 39 ++++++++++--------- ...eBusJmsConnectionFactoryConfiguration.java | 5 ++- ...ServiceBusJmsConnectionFactoryFactory.java | 6 ++- 3 files changed, 27 insertions(+), 23 deletions(-) diff --git a/sdk/spring/spring-cloud-azure-autoconfigure/src/main/java/com/azure/spring/cloud/autoconfigure/implementation/jms/ServiceBusJmsAutoConfiguration.java b/sdk/spring/spring-cloud-azure-autoconfigure/src/main/java/com/azure/spring/cloud/autoconfigure/implementation/jms/ServiceBusJmsAutoConfiguration.java index 4ec523784919..62e8c6128835 100644 --- a/sdk/spring/spring-cloud-azure-autoconfigure/src/main/java/com/azure/spring/cloud/autoconfigure/implementation/jms/ServiceBusJmsAutoConfiguration.java +++ b/sdk/spring/spring-cloud-azure-autoconfigure/src/main/java/com/azure/spring/cloud/autoconfigure/implementation/jms/ServiceBusJmsAutoConfiguration.java @@ -72,26 +72,27 @@ AzureServiceBusJmsProperties serviceBusJmsProperties(AzureGlobalProperties azure @ConditionalOnMissingBean AzureServiceBusJmsConnectionFactoryFactory azureServiceBusJmsConnectionFactoryFactory( final AzureServiceBusJmsProperties properties) { + if (!properties.isPasswordlessEnabled()) { + return () -> new ServiceBusJmsConnectionFactory( + properties.getConnectionString(), + new ServiceBusJmsConnectionFactorySettings()); + } + + String hostName = + properties.getNamespace() + + "." + + properties.getProfile().getEnvironment().getServiceBusDomainName(); + Properties passwordlessProperties = properties.toPasswordlessProperties(); + enhancePasswordlessProperties(AzureServiceBusJmsProperties.PREFIX, properties, passwordlessProperties); + TokenCredentialProvider tokenCredentialProvider = TokenCredentialProvider.createDefault( + new TokenCredentialProviderOptions(passwordlessProperties)); + return () -> { - if (properties.isPasswordlessEnabled()) { - String hostName = - properties.getNamespace() - + "." - + properties.getProfile().getEnvironment().getServiceBusDomainName(); - Properties passwordlessProperties = properties.toPasswordlessProperties(); - enhancePasswordlessProperties(AzureServiceBusJmsProperties.PREFIX, properties, passwordlessProperties); - TokenCredentialProvider tokenCredentialProvider = TokenCredentialProvider.createDefault( - new TokenCredentialProviderOptions(passwordlessProperties)); - TokenCredential tokenCredential = tokenCredentialProvider.get(); - return new ServiceBusJmsConnectionFactory( - tokenCredential, - hostName, - new ServiceBusJmsConnectionFactorySettings()); - } else { - return new ServiceBusJmsConnectionFactory( - properties.getConnectionString(), - new ServiceBusJmsConnectionFactorySettings()); - } + TokenCredential tokenCredential = tokenCredentialProvider.get(); + return new ServiceBusJmsConnectionFactory( + tokenCredential, + hostName, + new ServiceBusJmsConnectionFactorySettings()); }; } diff --git a/sdk/spring/spring-cloud-azure-autoconfigure/src/main/java/com/azure/spring/cloud/autoconfigure/implementation/jms/ServiceBusJmsConnectionFactoryConfiguration.java b/sdk/spring/spring-cloud-azure-autoconfigure/src/main/java/com/azure/spring/cloud/autoconfigure/implementation/jms/ServiceBusJmsConnectionFactoryConfiguration.java index 668409368e5a..06f404c34224 100644 --- a/sdk/spring/spring-cloud-azure-autoconfigure/src/main/java/com/azure/spring/cloud/autoconfigure/implementation/jms/ServiceBusJmsConnectionFactoryConfiguration.java +++ b/sdk/spring/spring-cloud-azure-autoconfigure/src/main/java/com/azure/spring/cloud/autoconfigure/implementation/jms/ServiceBusJmsConnectionFactoryConfiguration.java @@ -51,7 +51,7 @@ class ServiceBusJmsConnectionFactoryConfiguration { * * @param properties the Azure Service Bus JMS properties * @param customizers the list of customizers to apply - * @param instanceFactory the factory used to create the ServiceBusJmsConnectionFactory instance + * @param instanceFactory the factory used to create the ServiceBusJmsConnectionFactory instance * @return a configured ServiceBusJmsConnectionFactory instance */ static ServiceBusJmsConnectionFactory createServiceBusJmsConnectionFactory( @@ -198,7 +198,8 @@ private void registerJmsPoolConnectionFactory(BeanDefinitionRegistry registry) { private ServiceBusJmsConnectionFactory createServiceBusJmsConnectionFactory() { AzureServiceBusJmsProperties serviceBusJmsProperties = beanFactory.getBean(AzureServiceBusJmsProperties.class); - AzureServiceBusJmsConnectionFactoryFactory instanceFactory = beanFactory.getBean(AzureServiceBusJmsConnectionFactoryFactory.class); + AzureServiceBusJmsConnectionFactoryFactory instanceFactory = + beanFactory.getBean(AzureServiceBusJmsConnectionFactoryFactory.class); ObjectProvider factoryCustomizers = beanFactory.getBeanProvider(AzureServiceBusJmsConnectionFactoryCustomizer.class); return ServiceBusJmsConnectionFactoryConfiguration.createServiceBusJmsConnectionFactory( serviceBusJmsProperties, diff --git a/sdk/spring/spring-cloud-azure-autoconfigure/src/main/java/com/azure/spring/cloud/autoconfigure/implementation/jms/ServiceBusJmsConnectionFactoryFactory.java b/sdk/spring/spring-cloud-azure-autoconfigure/src/main/java/com/azure/spring/cloud/autoconfigure/implementation/jms/ServiceBusJmsConnectionFactoryFactory.java index e5f060bf11d8..1fefca5ad631 100644 --- a/sdk/spring/spring-cloud-azure-autoconfigure/src/main/java/com/azure/spring/cloud/autoconfigure/implementation/jms/ServiceBusJmsConnectionFactoryFactory.java +++ b/sdk/spring/spring-cloud-azure-autoconfigure/src/main/java/com/azure/spring/cloud/autoconfigure/implementation/jms/ServiceBusJmsConnectionFactoryFactory.java @@ -24,7 +24,8 @@ class ServiceBusJmsConnectionFactoryFactory { this.factoryCustomizers = (factoryCustomizers != null) ? factoryCustomizers : Collections.emptyList(); } - ServiceBusJmsConnectionFactory createConnectionFactory(AzureServiceBusJmsConnectionFactoryFactory instanceFactory) { + ServiceBusJmsConnectionFactory createConnectionFactory( + AzureServiceBusJmsConnectionFactoryFactory instanceFactory) { Assert.notNull(instanceFactory, "AzureServiceBusJmsConnectionFactoryFactory must not be null"); ServiceBusJmsConnectionFactory factory = createConnectionFactoryInstance(instanceFactory); Assert.notNull( @@ -54,7 +55,8 @@ private void setPrefetchPolicy(T fact String.valueOf(prefetchProperties.getTopicPrefetch())); } - private ServiceBusJmsConnectionFactory createConnectionFactoryInstance(AzureServiceBusJmsConnectionFactoryFactory instanceFactory) { + private ServiceBusJmsConnectionFactory createConnectionFactoryInstance( + AzureServiceBusJmsConnectionFactoryFactory instanceFactory) { return instanceFactory.createServiceBusJmsConnectionFactory(); } From 028d70950f04ff085491886d621c4941f56a1a8a Mon Sep 17 00:00:00 2001 From: Rujun Chen Date: Tue, 30 Jun 2026 15:03:50 +0800 Subject: [PATCH 6/7] [Spring] Fix JavaDoc indentation in JMS factory helper --- .../jms/ServiceBusJmsConnectionFactoryConfiguration.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sdk/spring/spring-cloud-azure-autoconfigure/src/main/java/com/azure/spring/cloud/autoconfigure/implementation/jms/ServiceBusJmsConnectionFactoryConfiguration.java b/sdk/spring/spring-cloud-azure-autoconfigure/src/main/java/com/azure/spring/cloud/autoconfigure/implementation/jms/ServiceBusJmsConnectionFactoryConfiguration.java index 06f404c34224..7ac37ba648a8 100644 --- a/sdk/spring/spring-cloud-azure-autoconfigure/src/main/java/com/azure/spring/cloud/autoconfigure/implementation/jms/ServiceBusJmsConnectionFactoryConfiguration.java +++ b/sdk/spring/spring-cloud-azure-autoconfigure/src/main/java/com/azure/spring/cloud/autoconfigure/implementation/jms/ServiceBusJmsConnectionFactoryConfiguration.java @@ -51,7 +51,7 @@ class ServiceBusJmsConnectionFactoryConfiguration { * * @param properties the Azure Service Bus JMS properties * @param customizers the list of customizers to apply - * @param instanceFactory the factory used to create the ServiceBusJmsConnectionFactory instance + * @param instanceFactory the factory used to create the ServiceBusJmsConnectionFactory instance * @return a configured ServiceBusJmsConnectionFactory instance */ static ServiceBusJmsConnectionFactory createServiceBusJmsConnectionFactory( From b1cebf9694befbd0fcb3a6f0b29a029715fc90c8 Mon Sep 17 00:00:00 2001 From: Rujun Chen Date: Tue, 30 Jun 2026 15:11:40 +0800 Subject: [PATCH 7/7] [Spring] Clarify JMS factory extension contract --- .../jms/ServiceBusJmsContainerConfiguration.java | 2 +- .../AzureServiceBusJmsConnectionFactoryFactory.java | 12 +++++++++++- 2 files changed, 12 insertions(+), 2 deletions(-) diff --git a/sdk/spring/spring-cloud-azure-autoconfigure/src/main/java/com/azure/spring/cloud/autoconfigure/implementation/jms/ServiceBusJmsContainerConfiguration.java b/sdk/spring/spring-cloud-azure-autoconfigure/src/main/java/com/azure/spring/cloud/autoconfigure/implementation/jms/ServiceBusJmsContainerConfiguration.java index 8fd5d3bcb8d3..abfb825aed06 100644 --- a/sdk/spring/spring-cloud-azure-autoconfigure/src/main/java/com/azure/spring/cloud/autoconfigure/implementation/jms/ServiceBusJmsContainerConfiguration.java +++ b/sdk/spring/spring-cloud-azure-autoconfigure/src/main/java/com/azure/spring/cloud/autoconfigure/implementation/jms/ServiceBusJmsContainerConfiguration.java @@ -72,7 +72,7 @@ class ServiceBusJmsContainerConfiguration implements DisposableBean { private final AzureServiceBusJmsConnectionFactoryFactory instanceFactory; private final Environment environment; private final JmsProperties jmsProperties; - + // Memoized dedicated listener container ConnectionFactory instances to avoid duplicates and enable lifecycle management // Use ConnectionFactory type instead of concrete types to avoid NoClassDefFoundError when optional dependencies are missing private volatile ConnectionFactory dedicatedCachingConnectionFactory; diff --git a/sdk/spring/spring-cloud-azure-autoconfigure/src/main/java/com/azure/spring/cloud/autoconfigure/jms/AzureServiceBusJmsConnectionFactoryFactory.java b/sdk/spring/spring-cloud-azure-autoconfigure/src/main/java/com/azure/spring/cloud/autoconfigure/jms/AzureServiceBusJmsConnectionFactoryFactory.java index cae5f531db02..8095c3a3adcf 100644 --- a/sdk/spring/spring-cloud-azure-autoconfigure/src/main/java/com/azure/spring/cloud/autoconfigure/jms/AzureServiceBusJmsConnectionFactoryFactory.java +++ b/sdk/spring/spring-cloud-azure-autoconfigure/src/main/java/com/azure/spring/cloud/autoconfigure/jms/AzureServiceBusJmsConnectionFactoryFactory.java @@ -6,7 +6,17 @@ import com.azure.servicebus.jms.ServiceBusJmsConnectionFactory; /** - * The interface used to define how the {@link ServiceBusJmsConnectionFactory} instance is created. + * Defines how a {@link ServiceBusJmsConnectionFactory} instance is created. + *

+ * Provide this interface as a Spring bean to customize creation of + * {@link ServiceBusJmsConnectionFactory} (or a subclass). + *

+ *

+ * The factory can be invoked multiple times in one application context + * (for example sender and listener container paths). Implementations should + * return a new {@link ServiceBusJmsConnectionFactory} instance per invocation, + * or otherwise ensure the returned instance is safe to share. + *

*/ @FunctionalInterface public interface AzureServiceBusJmsConnectionFactoryFactory {