Skip to content

Commit

Permalink
Fix bug: Property does not work when setting jms pool disabled (Azure…
Browse files Browse the repository at this point in the history
  • Loading branch information
moarychan authored Dec 16, 2024
1 parent 0430452 commit fd2e1bf
Show file tree
Hide file tree
Showing 41 changed files with 797 additions and 318 deletions.
1 change: 1 addition & 0 deletions sdk/spring/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ This section includes changes in `spring-cloud-azure-autoconfigure` module.
- Fix error: Service Bus connection string is still used when it's configured to empty string. [#42880](https://github.com/Azure/azure-sdk-for-java/issues/42880).
- Fix warn logs: Mark the bean post processor related beans as internal to avoid the log 'Bean xxx of type xxx is not eligible for getting processed by all BeanPostProcessors'. [#38631](https://github.com/Azure/azure-sdk-for-java/issues/38631).
- Fix missing bean `springTokenCredentialProviderContextProvider`: Azure Identity Extensions and Spring Cloud Stream Binder cannot work together. [#43147](https://github.com/Azure/azure-sdk-for-java/issues/43147).
- Fix bug: Property does not work when setting `spring.jms.servicebus.pool.enabled=false` using `@PropertySource`. [#43279](https://github.com/Azure/azure-sdk-for-java/issues/43279).

### Spring Integration Azure Core
This section includes changes in the `spring-integration-azure-core` module.
Expand Down

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,6 @@
import org.springframework.boot.autoconfigure.condition.ConditionalOnExpression;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.boot.autoconfigure.jms.JmsAutoConfiguration;
import org.springframework.boot.autoconfigure.jms.JmsProperties;
import org.springframework.boot.autoconfigure.jms.JndiConnectionFactoryAutoConfiguration;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.context.annotation.Bean;
Expand All @@ -47,11 +46,12 @@
AzureServiceBusResourceManagerAutoConfiguration.class })
@ConditionalOnProperty(value = "spring.jms.servicebus.enabled", matchIfMissing = true)
@ConditionalOnClass({ ConnectionFactory.class, JmsConnectionFactory.class, JmsTemplate.class })
@EnableConfigurationProperties({ JmsProperties.class })
@EnableConfigurationProperties
@Import({
ServiceBusJmsConnectionFactoryConfiguration.class,
ServiceBusJmsContainerConfiguration.class,
ServiceBusJmsPropertiesConfiguration.class })
ServiceBusJmsPropertiesConfiguration.class,
ServiceBusJmsConnectionFactoryConfiguration.class
})
public class ServiceBusJmsAutoConfiguration {

@Bean
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,77 +7,120 @@
import com.azure.spring.cloud.autoconfigure.implementation.jms.properties.AzureServiceBusJmsProperties;
import com.azure.spring.cloud.autoconfigure.jms.AzureServiceBusJmsConnectionFactoryCustomizer;
import jakarta.jms.ConnectionFactory;
import org.apache.commons.pool2.PooledObject;
import org.messaginghub.pooled.jms.JmsPoolConnectionFactory;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.BeanFactory;
import org.springframework.beans.factory.BeanFactoryAware;
import org.springframework.beans.factory.ObjectProvider;
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.beans.factory.support.BeanDefinitionBuilder;
import org.springframework.beans.factory.support.BeanDefinitionRegistry;
import org.springframework.boot.autoconfigure.jms.JmsPoolConnectionFactoryFactory;
import org.springframework.boot.autoconfigure.jms.JmsProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.boot.context.properties.bind.BindResult;
import org.springframework.boot.context.properties.bind.Binder;
import org.springframework.context.EnvironmentAware;
import org.springframework.context.annotation.Import;
import org.springframework.context.annotation.ImportBeanDefinitionRegistrar;
import org.springframework.core.env.Environment;
import org.springframework.core.type.AnnotationMetadata;
import org.springframework.jms.connection.CachingConnectionFactory;
import org.springframework.util.ClassUtils;

import java.util.stream.Collectors;

@Configuration(proxyBeanMethods = false)
@ConditionalOnMissingBean(ConnectionFactory.class)
class ServiceBusJmsConnectionFactoryConfiguration {
import static org.springframework.beans.factory.support.BeanDefinitionBuilder.genericBeanDefinition;

private ServiceBusJmsConnectionFactory createJmsConnectionFactory(AzureServiceBusJmsProperties serviceBusJmsProperties,
ObjectProvider<AzureServiceBusJmsConnectionFactoryCustomizer> factoryCustomizers) {
return new ServiceBusJmsConnectionFactoryFactory(serviceBusJmsProperties,
factoryCustomizers.orderedStream().collect(Collectors.toList()))
.createConnectionFactory(ServiceBusJmsConnectionFactory.class);
}
/**
* Configuration for {@link ConnectionFactory}.
*
* @since 5.19.0
*/
@Import(ServiceBusJmsConnectionFactoryConfiguration.Registrar.class)
class ServiceBusJmsConnectionFactoryConfiguration {

static class Registrar implements BeanFactoryAware, EnvironmentAware, ImportBeanDefinitionRegistrar {

@Configuration(proxyBeanMethods = false)
@ConditionalOnProperty(prefix = "spring.jms.servicebus.pool", name = "enabled", havingValue = "false",
matchIfMissing = true)
class SimpleConnectionFactoryConfiguration {
private Environment environment;
private BeanFactory beanFactory;
private static final String JMS_CONNECTION_FACTORY_BEAN_NAME = "jmsConnectionFactory";
private static final String JMS_POOL_CONNECTION_FACTORY_BEAN_NAME = "jmsPoolConnectionFactory";

@Override
public void setBeanFactory(BeanFactory beanFactory) throws BeansException {
this.beanFactory = beanFactory;
}

@Bean
@ConditionalOnProperty(prefix = "spring.jms.cache", name = "enabled", havingValue = "false")
ServiceBusJmsConnectionFactory jmsConnectionFactory(AzureServiceBusJmsProperties properties,
ObjectProvider<AzureServiceBusJmsConnectionFactoryCustomizer> factoryCustomizers) {
return createJmsConnectionFactory(properties, factoryCustomizers);
@Override
public void setEnvironment(Environment environment) {
this.environment = environment;
}

@Configuration(proxyBeanMethods = false)
@ConditionalOnClass(CachingConnectionFactory.class)
@ConditionalOnProperty(prefix = "spring.jms.cache", name = "enabled", havingValue = "true",
matchIfMissing = true)
class CachingConnectionFactoryConfiguration {

@Bean
CachingConnectionFactory jmsConnectionFactory(JmsProperties jmsProperties,
AzureServiceBusJmsProperties properties,
ObjectProvider<AzureServiceBusJmsConnectionFactoryCustomizer> factoryCustomizers) {
ServiceBusJmsConnectionFactory factory = createJmsConnectionFactory(properties, factoryCustomizers);
CachingConnectionFactory connectionFactory = new CachingConnectionFactory(factory);
JmsProperties.Cache cacheProperties = jmsProperties.getCache();
connectionFactory.setCacheConsumers(cacheProperties.isConsumers());
connectionFactory.setCacheProducers(cacheProperties.isProducers());
connectionFactory.setSessionCacheSize(cacheProperties.getSessionCacheSize());
return connectionFactory;
@Override
public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata,
BeanDefinitionRegistry registry) {
BindResult<Boolean> poolEnabledResult = Binder.get(environment).bind("spring.jms.servicebus.pool.enabled", Boolean.class);
BindResult<Boolean> cacheEnabledResult = Binder.get(environment).bind("spring.jms.cache.enabled", Boolean.class);

if (isPoolConnectionFactoryClassPresent()
&& ((!cacheEnabledResult.isBound() && !poolEnabledResult.isBound())) || poolEnabledResult.orElseGet(() -> false)) {
registerJmsPoolConnectionFactory(registry);
return;
}

if (isCacheConnectionFactoryClassPresent() && (!cacheEnabledResult.isBound() || cacheEnabledResult.orElseGet(() -> false))) {
registerJmsCachingConnectionFactory(registry);
return;
}

registerServiceBusJmsConnectionFactory(registry);
}

}
private static boolean isCacheConnectionFactoryClassPresent() {
return ClassUtils.isPresent("org.springframework.jms.connection.CachingConnectionFactory", null);
}

private static boolean isPoolConnectionFactoryClassPresent() {
return ClassUtils.isPresent("org.messaginghub.pooled.jms.JmsPoolConnectionFactory", null)
&& ClassUtils.isPresent("org.apache.commons.pool2.PooledObject", null);
}

private void registerServiceBusJmsConnectionFactory(BeanDefinitionRegistry registry) {
BeanDefinitionBuilder definitionBuilder = genericBeanDefinition(ServiceBusJmsConnectionFactory.class,
this::createServiceBusJmsConnectionFactory);
registry.registerBeanDefinition(JMS_CONNECTION_FACTORY_BEAN_NAME, definitionBuilder.getBeanDefinition());
}

private void registerJmsCachingConnectionFactory(BeanDefinitionRegistry registry) {
BeanDefinitionBuilder definitionBuilder = genericBeanDefinition(CachingConnectionFactory.class,
() -> {
CachingConnectionFactory connectionFactory = new CachingConnectionFactory(createServiceBusJmsConnectionFactory());
JmsProperties jmsProperties = beanFactory.getBean(JmsProperties.class);
JmsProperties.Cache cacheProperties = jmsProperties.getCache();
connectionFactory.setCacheConsumers(cacheProperties.isConsumers());
connectionFactory.setCacheProducers(cacheProperties.isProducers());
connectionFactory.setSessionCacheSize(cacheProperties.getSessionCacheSize());
return connectionFactory;
});
registry.registerBeanDefinition(JMS_CONNECTION_FACTORY_BEAN_NAME, definitionBuilder.getBeanDefinition());
}

private void registerJmsPoolConnectionFactory(BeanDefinitionRegistry registry) {
BeanDefinitionBuilder definitionBuilder = genericBeanDefinition(JmsPoolConnectionFactory.class,
() -> {
AzureServiceBusJmsProperties serviceBusJmsProperties = beanFactory.getBean(AzureServiceBusJmsProperties.class);
return new JmsPoolConnectionFactoryFactory(serviceBusJmsProperties.getPool())
.createPooledConnectionFactory(createServiceBusJmsConnectionFactory());
});
definitionBuilder.setDestroyMethodName("stop");
registry.registerBeanDefinition(JMS_POOL_CONNECTION_FACTORY_BEAN_NAME, definitionBuilder.getBeanDefinition());
}

@Configuration(proxyBeanMethods = false)
@ConditionalOnClass({ JmsPoolConnectionFactory.class, PooledObject.class })
class PooledConnectionFactoryConfiguration {

@Bean(destroyMethod = "stop")
@ConditionalOnProperty(prefix = "spring.jms.servicebus.pool", name = "enabled", havingValue = "true")
JmsPoolConnectionFactory jmsPoolConnectionFactory(AzureServiceBusJmsProperties properties,
ObjectProvider<AzureServiceBusJmsConnectionFactoryCustomizer> factoryCustomizers) {
ServiceBusJmsConnectionFactory factory = createJmsConnectionFactory(properties, factoryCustomizers);
return new JmsPoolConnectionFactoryFactory(properties.getPool())
.createPooledConnectionFactory(factory);
private ServiceBusJmsConnectionFactory createServiceBusJmsConnectionFactory() {
AzureServiceBusJmsProperties serviceBusJmsProperties = beanFactory.getBean(AzureServiceBusJmsProperties.class);
ObjectProvider<AzureServiceBusJmsConnectionFactoryCustomizer> factoryCustomizers = beanFactory.getBeanProvider(AzureServiceBusJmsConnectionFactoryCustomizer.class);
return new ServiceBusJmsConnectionFactoryFactory(serviceBusJmsProperties,
factoryCustomizers.orderedStream().collect(Collectors.toList()))
.createConnectionFactory(ServiceBusJmsConnectionFactory.class);
}
}
}
Original file line number Diff line number Diff line change
@@ -1,8 +1,7 @@
org.springframework.boot.env.EnvironmentPostProcessor=\
com.azure.spring.cloud.autoconfigure.implementation.context.AzureGlobalConfigurationEnvironmentPostProcessor,\
com.azure.spring.cloud.autoconfigure.implementation.keyvault.environment.KeyVaultEnvironmentPostProcessor,\
com.azure.spring.cloud.autoconfigure.implementation.passwordless.AzurePasswordlessEnvironmentPostProcessor,\
com.azure.spring.cloud.autoconfigure.implementation.jms.AzureServiceBusJmsPropertiesEnvironmentPostProcessor
com.azure.spring.cloud.autoconfigure.implementation.passwordless.AzurePasswordlessEnvironmentPostProcessor

org.springframework.boot.diagnostics.FailureAnalyzer=\
com.azure.spring.cloud.autoconfigure.implementation.compatibility.AzureCompatibilityNotMetFailureAnalyzer
Expand Down

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -41,14 +41,12 @@ class ServiceBusJmsAutoConfigurationTests {

static final String CONNECTION_STRING = "Endpoint=sb://host/;SharedAccessKeyName=sasKeyName;"
+ "SharedAccessKey=sasKey";
private final AzureServiceBusJmsPropertiesEnvironmentPostProcessor processor =
new AzureServiceBusJmsPropertiesEnvironmentPostProcessor();

private final ApplicationContextRunner contextRunner = new ApplicationContextRunner()
.withBean(AzureGlobalProperties.class, AzureGlobalProperties::new)
.withConfiguration(AutoConfigurations.of(
JmsAutoConfiguration.class,
ServiceBusJmsAutoConfiguration.class))
.withInitializer(context -> processor.postProcessEnvironment(context.getEnvironment(), null));
ServiceBusJmsAutoConfiguration.class));

private void testQueueJmsListenerContainerFactoryWithCustomSettings(AssertableApplicationContext loaded) {
DefaultJmsListenerContainerFactory listenerContainerFactory =
Expand Down
Loading

0 comments on commit fd2e1bf

Please sign in to comment.