Add support for JMS session caching

This commit adds support for CachingConnectionFactory for both Artemis
and ActiveMQ. If connection pooling is not enabled explicitly, sessions,
producers and consumers are cached. The factory can be further
customized, including reverting to the raw ConnectionFactory, using the
`spring.jms.*` namespace.

Closes gh-12161
pull/13534/head
Stephane Nicoll 7 years ago
parent 0ef54a79b1
commit 8365d53554

@ -1,5 +1,5 @@
/* /*
* Copyright 2012-2017 the original author or authors. * Copyright 2012-2018 the original author or authors.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@ -41,6 +41,8 @@ public class JmsProperties {
*/ */
private String jndiName; private String jndiName;
private final Cache cache = new Cache();
private final Listener listener = new Listener(); private final Listener listener = new Listener();
private final Template template = new Template(); private final Template template = new Template();
@ -61,6 +63,10 @@ public class JmsProperties {
this.jndiName = jndiName; this.jndiName = jndiName;
} }
public Cache getCache() {
return this.cache;
}
public Listener getListener() { public Listener getListener() {
return this.listener; return this.listener;
} }
@ -69,6 +75,62 @@ public class JmsProperties {
return this.template; return this.template;
} }
public static class Cache {
/**
* Whether to cache sessions.
*/
private boolean enabled = true;
/**
* Whether to cache message consumers.
*/
private boolean consumers = false;
/**
* Whether to cache message producers.
*/
private boolean producers = true;
/**
* Size of the session cache (per JMS Session type).
*/
private int sessionCacheSize = 1;
public boolean isEnabled() {
return this.enabled;
}
public void setEnabled(boolean enabled) {
this.enabled = enabled;
}
public boolean isConsumers() {
return this.consumers;
}
public void setConsumers(boolean consumers) {
this.consumers = consumers;
}
public boolean isProducers() {
return this.producers;
}
public void setProducers(boolean producers) {
this.producers = producers;
}
public int getSessionCacheSize() {
return this.sessionCacheSize;
}
public void setSessionCacheSize(int sessionCacheSize) {
this.sessionCacheSize = sessionCacheSize;
}
}
public static class Listener { public static class Listener {
/** /**

@ -1,5 +1,5 @@
/* /*
* Copyright 2012-2017 the original author or authors. * Copyright 2012-2018 the original author or authors.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@ -26,6 +26,7 @@ import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass; import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.boot.autoconfigure.jms.JmsAutoConfiguration; 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.autoconfigure.jms.JndiConnectionFactoryAutoConfiguration;
import org.springframework.boot.context.properties.EnableConfigurationProperties; import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.Configuration;
@ -45,7 +46,7 @@ import org.springframework.context.annotation.Import;
@AutoConfigureAfter({ JndiConnectionFactoryAutoConfiguration.class }) @AutoConfigureAfter({ JndiConnectionFactoryAutoConfiguration.class })
@ConditionalOnClass({ ConnectionFactory.class, ActiveMQConnectionFactory.class }) @ConditionalOnClass({ ConnectionFactory.class, ActiveMQConnectionFactory.class })
@ConditionalOnMissingBean(ConnectionFactory.class) @ConditionalOnMissingBean(ConnectionFactory.class)
@EnableConfigurationProperties(ActiveMQProperties.class) @EnableConfigurationProperties({ ActiveMQProperties.class, JmsProperties.class })
@Import({ ActiveMQXAConnectionFactoryConfiguration.class, @Import({ ActiveMQXAConnectionFactoryConfiguration.class,
ActiveMQConnectionFactoryConfiguration.class }) ActiveMQConnectionFactoryConfiguration.class })
public class ActiveMQAutoConfiguration { public class ActiveMQAutoConfiguration {

@ -28,8 +28,10 @@ import org.springframework.beans.factory.ObjectProvider;
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass; import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.boot.autoconfigure.jms.JmsProperties;
import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.Configuration;
import org.springframework.jms.connection.CachingConnectionFactory;
/** /**
* Configuration for ActiveMQ {@link ConnectionFactory}. * Configuration for ActiveMQ {@link ConnectionFactory}.
@ -45,15 +47,51 @@ import org.springframework.context.annotation.Configuration;
@ConditionalOnMissingBean(ConnectionFactory.class) @ConditionalOnMissingBean(ConnectionFactory.class)
class ActiveMQConnectionFactoryConfiguration { class ActiveMQConnectionFactoryConfiguration {
@Bean @Configuration
@ConditionalOnProperty(prefix = "spring.activemq.pool", name = "enabled", havingValue = "false", matchIfMissing = true) @ConditionalOnProperty(prefix = "spring.activemq.pool", name = "enabled", havingValue = "false", matchIfMissing = true)
public ActiveMQConnectionFactory jmsConnectionFactory(ActiveMQProperties properties, static class SimpleConnectionFactoryConfiguration {
ObjectProvider<List<ActiveMQConnectionFactoryCustomizer>> factoryCustomizers) {
return new ActiveMQConnectionFactoryFactory(properties, private final JmsProperties jmsProperties;
factoryCustomizers.getIfAvailable())
private final ActiveMQProperties properties;
private final List<ActiveMQConnectionFactoryCustomizer> connectionFactoryCustomizers;
SimpleConnectionFactoryConfiguration(JmsProperties jmsProperties,
ActiveMQProperties properties,
ObjectProvider<List<ActiveMQConnectionFactoryCustomizer>> connectionFactoryCustomizers) {
this.jmsProperties = jmsProperties;
this.properties = properties;
this.connectionFactoryCustomizers = connectionFactoryCustomizers
.getIfAvailable();
}
@Bean
@ConditionalOnProperty(prefix = "spring.jms.cache", name = "enabled", havingValue = "true", matchIfMissing = true)
public CachingConnectionFactory cachingJmsConnectionFactory() {
JmsProperties.Cache cacheProperties = this.jmsProperties.getCache();
CachingConnectionFactory connectionFactory = new CachingConnectionFactory(
createConnectionFactory());
connectionFactory.setCacheConsumers(cacheProperties.isConsumers());
connectionFactory.setCacheProducers(cacheProperties.isProducers());
connectionFactory.setSessionCacheSize(cacheProperties.getSessionCacheSize());
return connectionFactory;
}
@Bean
@ConditionalOnProperty(prefix = "spring.jms.cache", name = "enabled", havingValue = "false")
public ActiveMQConnectionFactory jmsConnectionFactory() {
return createConnectionFactory();
}
private ActiveMQConnectionFactory createConnectionFactory() {
return new ActiveMQConnectionFactoryFactory(this.properties,
this.connectionFactoryCustomizers)
.createConnectionFactory(ActiveMQConnectionFactory.class); .createConnectionFactory(ActiveMQConnectionFactory.class);
} }
}
@Configuration @Configuration
@ConditionalOnClass({ PooledConnectionFactory.class, PooledObject.class }) @ConditionalOnClass({ PooledConnectionFactory.class, PooledObject.class })
static class PooledConnectionFactoryConfiguration { static class PooledConnectionFactoryConfiguration {

@ -1,5 +1,5 @@
/* /*
* Copyright 2012-2017 the original author or authors. * Copyright 2012-2018 the original author or authors.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@ -26,6 +26,7 @@ import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass; import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.boot.autoconfigure.jms.JmsAutoConfiguration; 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.autoconfigure.jms.JndiConnectionFactoryAutoConfiguration;
import org.springframework.boot.context.properties.EnableConfigurationProperties; import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.Configuration;
@ -47,7 +48,7 @@ import org.springframework.context.annotation.Import;
@AutoConfigureAfter({ JndiConnectionFactoryAutoConfiguration.class }) @AutoConfigureAfter({ JndiConnectionFactoryAutoConfiguration.class })
@ConditionalOnClass({ ConnectionFactory.class, ActiveMQConnectionFactory.class }) @ConditionalOnClass({ ConnectionFactory.class, ActiveMQConnectionFactory.class })
@ConditionalOnMissingBean(ConnectionFactory.class) @ConditionalOnMissingBean(ConnectionFactory.class)
@EnableConfigurationProperties(ArtemisProperties.class) @EnableConfigurationProperties({ ArtemisProperties.class, JmsProperties.class })
@Import({ ArtemisEmbeddedServerConfiguration.class, @Import({ ArtemisEmbeddedServerConfiguration.class,
ArtemisXAConnectionFactoryConfiguration.class, ArtemisXAConnectionFactoryConfiguration.class,
ArtemisConnectionFactoryConfiguration.class }) ArtemisConnectionFactoryConfiguration.class })

@ -26,9 +26,11 @@ import org.springframework.beans.factory.ListableBeanFactory;
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass; import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.boot.autoconfigure.jms.JmsProperties;
import org.springframework.boot.autoconfigure.jms.activemq.PooledConnectionFactoryFactory; import org.springframework.boot.autoconfigure.jms.activemq.PooledConnectionFactoryFactory;
import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.Configuration;
import org.springframework.jms.connection.CachingConnectionFactory;
/** /**
* Configuration for Artemis {@link ConnectionFactory}. * Configuration for Artemis {@link ConnectionFactory}.
@ -41,14 +43,48 @@ import org.springframework.context.annotation.Configuration;
@ConditionalOnMissingBean(ConnectionFactory.class) @ConditionalOnMissingBean(ConnectionFactory.class)
class ArtemisConnectionFactoryConfiguration { class ArtemisConnectionFactoryConfiguration {
@Bean @Configuration
@ConditionalOnProperty(prefix = "spring.artemis.pool", name = "enabled", havingValue = "false", matchIfMissing = true) @ConditionalOnProperty(prefix = "spring.artemis.pool", name = "enabled", havingValue = "false", matchIfMissing = true)
public ActiveMQConnectionFactory jmsConnectionFactory(ListableBeanFactory beanFactory, static class SimpleConnectionFactoryConfiguration {
ArtemisProperties properties) {
return new ArtemisConnectionFactoryFactory(beanFactory, properties) private final JmsProperties jmsProperties;
private final ArtemisProperties properties;
private final ListableBeanFactory beanFactory;
SimpleConnectionFactoryConfiguration(JmsProperties jmsProperties,
ArtemisProperties properties, ListableBeanFactory beanFactory) {
this.jmsProperties = jmsProperties;
this.properties = properties;
this.beanFactory = beanFactory;
}
@Bean
@ConditionalOnProperty(prefix = "spring.jms.cache", name = "enabled", havingValue = "true", matchIfMissing = true)
public CachingConnectionFactory cachingJmsConnectionFactory() {
JmsProperties.Cache cacheProperties = this.jmsProperties.getCache();
CachingConnectionFactory connectionFactory = new CachingConnectionFactory(
createConnectionFactory());
connectionFactory.setCacheConsumers(cacheProperties.isConsumers());
connectionFactory.setCacheProducers(cacheProperties.isProducers());
connectionFactory.setSessionCacheSize(cacheProperties.getSessionCacheSize());
return connectionFactory;
}
@Bean
@ConditionalOnProperty(prefix = "spring.jms.cache", name = "enabled", havingValue = "false")
public ActiveMQConnectionFactory jmsConnectionFactory() {
return createConnectionFactory();
}
private ActiveMQConnectionFactory createConnectionFactory() {
return new ArtemisConnectionFactoryFactory(this.beanFactory, this.properties)
.createConnectionFactory(ActiveMQConnectionFactory.class); .createConnectionFactory(ActiveMQConnectionFactory.class);
} }
}
@Configuration @Configuration
@ConditionalOnClass({ PooledConnectionFactory.class, PooledObject.class }) @ConditionalOnClass({ PooledConnectionFactory.class, PooledObject.class })
static class PooledConnectionFactoryConfiguration { static class PooledConnectionFactoryConfiguration {

@ -40,6 +40,7 @@ import org.springframework.jms.config.JmsListenerConfigUtils;
import org.springframework.jms.config.JmsListenerContainerFactory; import org.springframework.jms.config.JmsListenerContainerFactory;
import org.springframework.jms.config.JmsListenerEndpoint; import org.springframework.jms.config.JmsListenerEndpoint;
import org.springframework.jms.config.SimpleJmsListenerContainerFactory; import org.springframework.jms.config.SimpleJmsListenerContainerFactory;
import org.springframework.jms.connection.CachingConnectionFactory;
import org.springframework.jms.core.JmsMessagingTemplate; import org.springframework.jms.core.JmsMessagingTemplate;
import org.springframework.jms.core.JmsTemplate; import org.springframework.jms.core.JmsTemplate;
import org.springframework.jms.listener.DefaultMessageListenerContainer; import org.springframework.jms.listener.DefaultMessageListenerContainer;
@ -74,15 +75,17 @@ public class JmsAutoConfigurationTests {
} }
private void testDefaultJmsConfiguration(AssertableApplicationContext loaded) { private void testDefaultJmsConfiguration(AssertableApplicationContext loaded) {
ActiveMQConnectionFactory factory = loaded assertThat(loaded).hasSingleBean(ConnectionFactory.class);
.getBean(ActiveMQConnectionFactory.class); assertThat(loaded).hasSingleBean(CachingConnectionFactory.class);
CachingConnectionFactory factory = loaded.getBean(CachingConnectionFactory.class);
assertThat(factory.getTargetConnectionFactory())
.isInstanceOf(ActiveMQConnectionFactory.class);
JmsTemplate jmsTemplate = loaded.getBean(JmsTemplate.class); JmsTemplate jmsTemplate = loaded.getBean(JmsTemplate.class);
JmsMessagingTemplate messagingTemplate = loaded JmsMessagingTemplate messagingTemplate = loaded
.getBean(JmsMessagingTemplate.class); .getBean(JmsMessagingTemplate.class);
assertThat(factory).isEqualTo(jmsTemplate.getConnectionFactory()); assertThat(factory).isEqualTo(jmsTemplate.getConnectionFactory());
assertThat(messagingTemplate.getJmsTemplate()).isEqualTo(jmsTemplate); assertThat(messagingTemplate.getJmsTemplate()).isEqualTo(jmsTemplate);
assertThat(((ActiveMQConnectionFactory) jmsTemplate.getConnectionFactory()) assertThat(getBrokerUrl(factory)).isEqualTo(ACTIVEMQ_EMBEDDED_URL);
.getBrokerURL()).isEqualTo(ACTIVEMQ_EMBEDDED_URL);
assertThat(loaded.containsBean("jmsListenerContainerFactory")).isTrue(); assertThat(loaded.containsBean("jmsListenerContainerFactory")).isTrue();
} }
@ -313,9 +316,10 @@ public class JmsAutoConfigurationTests {
public void testPubSubDomainOverride() { public void testPubSubDomainOverride() {
this.contextRunner.withUserConfiguration(TestConfiguration.class) this.contextRunner.withUserConfiguration(TestConfiguration.class)
.withPropertyValues("spring.jms.pubSubDomain:false").run((context) -> { .withPropertyValues("spring.jms.pubSubDomain:false").run((context) -> {
assertThat(context).hasSingleBean(JmsTemplate.class);
assertThat(context).hasSingleBean(ConnectionFactory.class);
JmsTemplate jmsTemplate = context.getBean(JmsTemplate.class); JmsTemplate jmsTemplate = context.getBean(JmsTemplate.class);
ActiveMQConnectionFactory factory = context ConnectionFactory factory = context.getBean(ConnectionFactory.class);
.getBean(ActiveMQConnectionFactory.class);
assertThat(jmsTemplate).isNotNull(); assertThat(jmsTemplate).isNotNull();
assertThat(jmsTemplate.isPubSubDomain()).isFalse(); assertThat(jmsTemplate.isPubSubDomain()).isFalse();
assertThat(factory).isNotNull() assertThat(factory).isNotNull()
@ -327,14 +331,12 @@ public class JmsAutoConfigurationTests {
public void testActiveMQOverriddenStandalone() { public void testActiveMQOverriddenStandalone() {
this.contextRunner.withUserConfiguration(TestConfiguration.class) this.contextRunner.withUserConfiguration(TestConfiguration.class)
.withPropertyValues("spring.activemq.inMemory:false").run((context) -> { .withPropertyValues("spring.activemq.inMemory:false").run((context) -> {
assertThat(context).hasSingleBean(JmsTemplate.class);
assertThat(context).hasSingleBean(CachingConnectionFactory.class);
JmsTemplate jmsTemplate = context.getBean(JmsTemplate.class); JmsTemplate jmsTemplate = context.getBean(JmsTemplate.class);
ActiveMQConnectionFactory factory = context ConnectionFactory factory = context.getBean(ConnectionFactory.class);
.getBean(ActiveMQConnectionFactory.class); assertThat(factory).isEqualTo(jmsTemplate.getConnectionFactory());
assertThat(jmsTemplate).isNotNull(); assertThat(getBrokerUrl((CachingConnectionFactory) factory))
assertThat(factory).isNotNull()
.isEqualTo(jmsTemplate.getConnectionFactory());
assertThat(((ActiveMQConnectionFactory) jmsTemplate
.getConnectionFactory()).getBrokerURL())
.isEqualTo(ACTIVEMQ_NETWORK_URL); .isEqualTo(ACTIVEMQ_NETWORK_URL);
}); });
} }
@ -344,18 +346,23 @@ public class JmsAutoConfigurationTests {
this.contextRunner.withUserConfiguration(TestConfiguration.class) this.contextRunner.withUserConfiguration(TestConfiguration.class)
.withPropertyValues("spring.activemq.brokerUrl:tcp://remote-host:10000") .withPropertyValues("spring.activemq.brokerUrl:tcp://remote-host:10000")
.run((context) -> { .run((context) -> {
assertThat(context).hasSingleBean(JmsTemplate.class);
assertThat(context).hasSingleBean(CachingConnectionFactory.class);
JmsTemplate jmsTemplate = context.getBean(JmsTemplate.class); JmsTemplate jmsTemplate = context.getBean(JmsTemplate.class);
ActiveMQConnectionFactory factory = context ConnectionFactory factory = context.getBean(ConnectionFactory.class);
.getBean(ActiveMQConnectionFactory.class);
assertThat(jmsTemplate).isNotNull();
assertThat(factory).isNotNull();
assertThat(factory).isEqualTo(jmsTemplate.getConnectionFactory()); assertThat(factory).isEqualTo(jmsTemplate.getConnectionFactory());
assertThat(((ActiveMQConnectionFactory) jmsTemplate assertThat(getBrokerUrl((CachingConnectionFactory) factory))
.getConnectionFactory()).getBrokerURL())
.isEqualTo("tcp://remote-host:10000"); .isEqualTo("tcp://remote-host:10000");
}); });
} }
private String getBrokerUrl(CachingConnectionFactory connectionFactory) {
assertThat(connectionFactory.getTargetConnectionFactory())
.isInstanceOf(ActiveMQConnectionFactory.class);
return ((ActiveMQConnectionFactory) connectionFactory
.getTargetConnectionFactory()).getBrokerURL();
}
@Test @Test
public void testActiveMQOverriddenPool() { public void testActiveMQOverriddenPool() {
this.contextRunner.withUserConfiguration(TestConfiguration.class) this.contextRunner.withUserConfiguration(TestConfiguration.class)

@ -27,6 +27,8 @@ import org.springframework.boot.autoconfigure.jms.JmsAutoConfiguration;
import org.springframework.boot.test.context.runner.ApplicationContextRunner; import org.springframework.boot.test.context.runner.ApplicationContextRunner;
import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.Configuration;
import org.springframework.jms.connection.CachingConnectionFactory;
import org.springframework.test.util.ReflectionTestUtils;
import org.springframework.util.StringUtils; import org.springframework.util.StringUtils;
import static org.assertj.core.api.Assertions.assertThat; import static org.assertj.core.api.Assertions.assertThat;
@ -50,10 +52,13 @@ public class ActiveMQAutoConfigurationTests {
public void brokerIsEmbeddedByDefault() { public void brokerIsEmbeddedByDefault() {
this.contextRunner.withUserConfiguration(EmptyConfiguration.class) this.contextRunner.withUserConfiguration(EmptyConfiguration.class)
.run((context) -> { .run((context) -> {
assertThat(context).getBean(ConnectionFactory.class) assertThat(context).hasSingleBean(CachingConnectionFactory.class);
CachingConnectionFactory cachingConnectionFactory = context
.getBean(CachingConnectionFactory.class);
assertThat(cachingConnectionFactory.getTargetConnectionFactory())
.isInstanceOf(ActiveMQConnectionFactory.class); .isInstanceOf(ActiveMQConnectionFactory.class);
assertThat(context.getBean(ActiveMQConnectionFactory.class) assertThat(((ActiveMQConnectionFactory) cachingConnectionFactory
.getBrokerURL()) .getTargetConnectionFactory()).getBrokerURL())
.isEqualTo("vm://localhost?broker.persistent=false"); .isEqualTo("vm://localhost?broker.persistent=false");
}); });
} }
@ -68,10 +73,46 @@ public class ActiveMQAutoConfigurationTests {
} }
@Test @Test
public void defaultConnectionFactoryIsApplied() { public void connectionFactoryIsCachedByDefault() {
this.contextRunner.withUserConfiguration(EmptyConfiguration.class) this.contextRunner.withUserConfiguration(EmptyConfiguration.class)
.withPropertyValues("spring.activemq.pool.enabled=false")
.run((context) -> { .run((context) -> {
assertThat(context).hasSingleBean(ConnectionFactory.class);
assertThat(context).hasSingleBean(CachingConnectionFactory.class);
CachingConnectionFactory connectionFactory = context
.getBean(CachingConnectionFactory.class);
assertThat(connectionFactory.getTargetConnectionFactory())
.isInstanceOf(ActiveMQConnectionFactory.class);
assertThat(ReflectionTestUtils.getField(connectionFactory,
"cacheConsumers")).isEqualTo(false);
assertThat(ReflectionTestUtils.getField(connectionFactory,
"cacheProducers")).isEqualTo(true);
assertThat(connectionFactory.getSessionCacheSize()).isEqualTo(1);
});
}
@Test
public void connectionFactoryCachingCanBeCustomized() {
this.contextRunner.withUserConfiguration(EmptyConfiguration.class)
.withPropertyValues("spring.jms.cache.consumers=true",
"spring.jms.cache.producers=false",
"spring.jms.cache.session-cache-size=10")
.run((context) -> {
assertThat(context).hasSingleBean(ConnectionFactory.class);
assertThat(context).hasSingleBean(CachingConnectionFactory.class);
CachingConnectionFactory connectionFactory = context
.getBean(CachingConnectionFactory.class);
assertThat(ReflectionTestUtils.getField(connectionFactory,
"cacheConsumers")).isEqualTo(true);
assertThat(ReflectionTestUtils.getField(connectionFactory,
"cacheProducers")).isEqualTo(false);
assertThat(connectionFactory.getSessionCacheSize()).isEqualTo(10);
});
}
@Test
public void connectionFactoryCachingCanBeDisabled() {
this.contextRunner.withUserConfiguration(EmptyConfiguration.class)
.withPropertyValues("spring.jms.cache.enabled=false").run((context) -> {
assertThat(context.getBeansOfType(ActiveMQConnectionFactory.class)) assertThat(context.getBeansOfType(ActiveMQConnectionFactory.class))
.hasSize(1); .hasSize(1);
ActiveMQConnectionFactory connectionFactory = context ActiveMQConnectionFactory connectionFactory = context
@ -99,7 +140,7 @@ public class ActiveMQAutoConfigurationTests {
@Test @Test
public void customConnectionFactoryIsApplied() { public void customConnectionFactoryIsApplied() {
this.contextRunner.withUserConfiguration(EmptyConfiguration.class) this.contextRunner.withUserConfiguration(EmptyConfiguration.class)
.withPropertyValues("spring.activemq.pool.enabled=false", .withPropertyValues("spring.jms.cache.enabled=false",
"spring.activemq.brokerUrl=vm://localhost?useJmx=false&broker.persistent=false", "spring.activemq.brokerUrl=vm://localhost?useJmx=false&broker.persistent=false",
"spring.activemq.user=foo", "spring.activemq.password=bar", "spring.activemq.user=foo", "spring.activemq.password=bar",
"spring.activemq.closeTimeout=500", "spring.activemq.closeTimeout=500",

@ -48,10 +48,12 @@ import org.springframework.boot.test.context.runner.ApplicationContextRunner;
import org.springframework.context.ApplicationContext; import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.Configuration;
import org.springframework.jms.connection.CachingConnectionFactory;
import org.springframework.jms.core.JmsTemplate; import org.springframework.jms.core.JmsTemplate;
import org.springframework.jms.core.SessionCallback; import org.springframework.jms.core.SessionCallback;
import org.springframework.jms.support.destination.DestinationResolver; import org.springframework.jms.support.destination.DestinationResolver;
import org.springframework.jms.support.destination.DynamicDestinationResolver; import org.springframework.jms.support.destination.DynamicDestinationResolver;
import org.springframework.test.util.ReflectionTestUtils;
import static org.assertj.core.api.Assertions.assertThat; import static org.assertj.core.api.Assertions.assertThat;
@ -70,17 +72,69 @@ public class ArtemisAutoConfigurationTests {
.withConfiguration(AutoConfigurations.of(ArtemisAutoConfiguration.class, .withConfiguration(AutoConfigurations.of(ArtemisAutoConfiguration.class,
JmsAutoConfiguration.class)); JmsAutoConfiguration.class));
@Test
public void connectionFactoryIsCachedByDefault() {
this.contextRunner.withUserConfiguration(EmptyConfiguration.class)
.run((context) -> {
assertThat(context).hasSingleBean(ConnectionFactory.class);
assertThat(context).hasSingleBean(CachingConnectionFactory.class);
CachingConnectionFactory connectionFactory = context
.getBean(CachingConnectionFactory.class);
assertThat(connectionFactory.getTargetConnectionFactory())
.isInstanceOf(ActiveMQConnectionFactory.class);
assertThat(ReflectionTestUtils.getField(connectionFactory,
"cacheConsumers")).isEqualTo(false);
assertThat(ReflectionTestUtils.getField(connectionFactory,
"cacheProducers")).isEqualTo(true);
assertThat(connectionFactory.getSessionCacheSize()).isEqualTo(1);
});
}
@Test
public void connectionFactoryCachingCanBeCustomized() {
this.contextRunner.withUserConfiguration(EmptyConfiguration.class)
.withPropertyValues("spring.jms.cache.consumers=true",
"spring.jms.cache.producers=false",
"spring.jms.cache.session-cache-size=10")
.run((context) -> {
assertThat(context).hasSingleBean(ConnectionFactory.class);
assertThat(context).hasSingleBean(CachingConnectionFactory.class);
CachingConnectionFactory connectionFactory = context
.getBean(CachingConnectionFactory.class);
assertThat(ReflectionTestUtils.getField(connectionFactory,
"cacheConsumers")).isEqualTo(true);
assertThat(ReflectionTestUtils.getField(connectionFactory,
"cacheProducers")).isEqualTo(false);
assertThat(connectionFactory.getSessionCacheSize()).isEqualTo(10);
});
}
@Test
public void connectionFactoryCachingCanBeDisabled() {
this.contextRunner.withUserConfiguration(EmptyConfiguration.class)
.withPropertyValues("spring.jms.cache.enabled=false").run((context) -> {
assertThat(context).hasSingleBean(ConnectionFactory.class);
assertThat(context).doesNotHaveBean(CachingConnectionFactory.class);
assertThat(context.getBean(ConnectionFactory.class))
.isInstanceOf(ActiveMQConnectionFactory.class);
});
}
@Test @Test
public void nativeConnectionFactory() { public void nativeConnectionFactory() {
this.contextRunner.withUserConfiguration(EmptyConfiguration.class) this.contextRunner.withUserConfiguration(EmptyConfiguration.class)
.withPropertyValues("spring.artemis.mode:native").run((context) -> { .withPropertyValues("spring.artemis.mode:native").run((context) -> {
JmsTemplate jmsTemplate = context.getBean(JmsTemplate.class); JmsTemplate jmsTemplate = context.getBean(JmsTemplate.class);
ActiveMQConnectionFactory factory = context ConnectionFactory connectionFactory = context
.getBean(ActiveMQConnectionFactory.class); .getBean(ConnectionFactory.class);
assertThat(factory).isEqualTo(jmsTemplate.getConnectionFactory()); assertThat(connectionFactory)
assertNettyConnectionFactory(factory, "localhost", 61616); .isEqualTo(jmsTemplate.getConnectionFactory());
assertThat(factory.getUser()).isNull(); ActiveMQConnectionFactory activeMQConnectionFactory = getActiveMQConnectionFactory(
assertThat(factory.getPassword()).isNull(); connectionFactory);
assertNettyConnectionFactory(activeMQConnectionFactory, "localhost",
61616);
assertThat(activeMQConnectionFactory.getUser()).isNull();
assertThat(activeMQConnectionFactory.getPassword()).isNull();
}); });
} }
@ -90,9 +144,10 @@ public class ArtemisAutoConfigurationTests {
.withPropertyValues("spring.artemis.mode:native", .withPropertyValues("spring.artemis.mode:native",
"spring.artemis.host:192.168.1.144", "spring.artemis.port:9876") "spring.artemis.host:192.168.1.144", "spring.artemis.port:9876")
.run((context) -> { .run((context) -> {
ActiveMQConnectionFactory factory = context assertNettyConnectionFactory(
.getBean(ActiveMQConnectionFactory.class); getActiveMQConnectionFactory(
assertNettyConnectionFactory(factory, "192.168.1.144", 9876); context.getBean(ConnectionFactory.class)),
"192.168.1.144", 9876);
}); });
} }
@ -103,12 +158,17 @@ public class ArtemisAutoConfigurationTests {
"spring.artemis.user:user", "spring.artemis.password:secret") "spring.artemis.user:user", "spring.artemis.password:secret")
.run((context) -> { .run((context) -> {
JmsTemplate jmsTemplate = context.getBean(JmsTemplate.class); JmsTemplate jmsTemplate = context.getBean(JmsTemplate.class);
ActiveMQConnectionFactory factory = context ConnectionFactory connectionFactory = context
.getBean(ActiveMQConnectionFactory.class); .getBean(ConnectionFactory.class);
assertThat(factory).isEqualTo(jmsTemplate.getConnectionFactory()); assertThat(connectionFactory)
assertNettyConnectionFactory(factory, "localhost", 61616); .isEqualTo(jmsTemplate.getConnectionFactory());
assertThat(factory.getUser()).isEqualTo("user"); ActiveMQConnectionFactory activeMQConnectionFactory = getActiveMQConnectionFactory(
assertThat(factory.getPassword()).isEqualTo("secret"); connectionFactory);
assertNettyConnectionFactory(activeMQConnectionFactory, "localhost",
61616);
assertThat(activeMQConnectionFactory.getUser()).isEqualTo("user");
assertThat(activeMQConnectionFactory.getPassword())
.isEqualTo("secret");
}); });
} }
@ -125,9 +185,8 @@ public class ArtemisAutoConfigurationTests {
org.apache.activemq.artemis.core.config.Configuration.class); org.apache.activemq.artemis.core.config.Configuration.class);
assertThat(configuration.isPersistenceEnabled()).isFalse(); assertThat(configuration.isPersistenceEnabled()).isFalse();
assertThat(configuration.isSecurityEnabled()).isFalse(); assertThat(configuration.isSecurityEnabled()).isFalse();
ActiveMQConnectionFactory factory = context assertInVmConnectionFactory(getActiveMQConnectionFactory(
.getBean(ActiveMQConnectionFactory.class); context.getBean(ConnectionFactory.class)));
assertInVmConnectionFactory(factory);
}); });
} }
@ -142,9 +201,8 @@ public class ArtemisAutoConfigurationTests {
org.apache.activemq.artemis.core.config.Configuration.class); org.apache.activemq.artemis.core.config.Configuration.class);
assertThat(configuration.isPersistenceEnabled()).isFalse(); assertThat(configuration.isPersistenceEnabled()).isFalse();
assertThat(configuration.isSecurityEnabled()).isFalse(); assertThat(configuration.isSecurityEnabled()).isFalse();
ActiveMQConnectionFactory factory = context assertInVmConnectionFactory(getActiveMQConnectionFactory(
.getBean(ActiveMQConnectionFactory.class); context.getBean(ConnectionFactory.class)));
assertInVmConnectionFactory(factory);
}); });
} }
@ -155,9 +213,10 @@ public class ArtemisAutoConfigurationTests {
.withPropertyValues("spring.artemis.embedded.enabled:false") .withPropertyValues("spring.artemis.embedded.enabled:false")
.run((context) -> { .run((context) -> {
assertThat(context).doesNotHaveBean(EmbeddedJMS.class); assertThat(context).doesNotHaveBean(EmbeddedJMS.class);
ActiveMQConnectionFactory factory = context assertNettyConnectionFactory(
.getBean(ActiveMQConnectionFactory.class); getActiveMQConnectionFactory(
assertNettyConnectionFactory(factory, "localhost", 61616); context.getBean(ConnectionFactory.class)),
"localhost", 61616);
}); });
} }
@ -169,9 +228,8 @@ public class ArtemisAutoConfigurationTests {
"spring.artemis.embedded.enabled:false") "spring.artemis.embedded.enabled:false")
.run((context) -> { .run((context) -> {
assertThat(context.getBeansOfType(EmbeddedJMS.class)).isEmpty(); assertThat(context.getBeansOfType(EmbeddedJMS.class)).isEmpty();
ActiveMQConnectionFactory connectionFactory = context assertInVmConnectionFactory(getActiveMQConnectionFactory(
.getBean(ActiveMQConnectionFactory.class); context.getBean(ConnectionFactory.class)));
assertInVmConnectionFactory(connectionFactory);
}); });
} }
@ -374,6 +432,13 @@ public class ArtemisAutoConfigurationTests {
}); });
} }
private ActiveMQConnectionFactory getActiveMQConnectionFactory(
ConnectionFactory connectionFactory) {
assertThat(connectionFactory).isInstanceOf(CachingConnectionFactory.class);
return (ActiveMQConnectionFactory) ((CachingConnectionFactory) connectionFactory)
.getTargetConnectionFactory();
}
private TransportConfiguration assertInVmConnectionFactory( private TransportConfiguration assertInVmConnectionFactory(
ActiveMQConnectionFactory connectionFactory) { ActiveMQConnectionFactory connectionFactory) {
TransportConfiguration transportConfig = getSingleTransportConfiguration( TransportConfiguration transportConfig = getSingleTransportConfiguration(

@ -995,6 +995,10 @@ content into your application. Rather, pick only the properties that you need.
spring.integration.jdbc.schema=classpath:org/springframework/integration/jdbc/schema-@@platform@@.sql # Path to the SQL file to use to initialize the database schema. spring.integration.jdbc.schema=classpath:org/springframework/integration/jdbc/schema-@@platform@@.sql # Path to the SQL file to use to initialize the database schema.
# JMS ({sc-spring-boot-autoconfigure}/jms/JmsProperties.{sc-ext}[JmsProperties]) # JMS ({sc-spring-boot-autoconfigure}/jms/JmsProperties.{sc-ext}[JmsProperties])
spring.jms.cache.consumers=false # Whether to cache message consumers.
spring.jms.cache.enabled=true # Whether to cache sessions.
spring.jms.cache.producers=true # Whether to cache message producers.
spring.jms.cache.session-cache-size=1 # Size of the session cache (per JMS Session type).
spring.jms.jndi-name= # Connection factory JNDI name. When set, takes precedence to others connection factory auto-configurations. spring.jms.jndi-name= # Connection factory JNDI name. When set, takes precedence to others connection factory auto-configurations.
spring.jms.listener.acknowledge-mode= # Acknowledge mode of the container. By default, the listener is transacted with automatic acknowledgment. spring.jms.listener.acknowledge-mode= # Acknowledge mode of the container. By default, the listener is transacted with automatic acknowledgment.
spring.jms.listener.auto-startup=true # Start the container automatically on startup. spring.jms.listener.auto-startup=true # Start the container automatically on startup.

@ -5065,7 +5065,16 @@ ActiveMQ configuration is controlled by external configuration properties in
spring.activemq.password=secret spring.activemq.password=secret
---- ----
You can also pool JMS resources by adding a dependency to By default, a `CachingConnectionFactory` wraps the native `ConnectionFactory` with
sensible settings that you can control by external configuration properties in
`+spring.jms.*+`:
[source,properties,indent=0]
----
spring.jms.cache.session-cache-size=5
----
If you'd rather use native pooling, you can do so by adding a dependency to
`org.apache.activemq:activemq-jms-pool` and configuring the `PooledConnectionFactory` `org.apache.activemq:activemq-jms-pool` and configuring the `PooledConnectionFactory`
accordingly, as shown in the following example: accordingly, as shown in the following example:
@ -5122,7 +5131,16 @@ list to create them with the default options, or you can define bean(s) of type
`org.apache.activemq.artemis.jms.server.config.TopicConfiguration`, for advanced queue `org.apache.activemq.artemis.jms.server.config.TopicConfiguration`, for advanced queue
and topic configurations, respectively. and topic configurations, respectively.
You can also pool JMS resources by adding a dependency to By default, a `CachingConnectionFactory` wraps the native `ConnectionFactory` with
sensible settings that you can control by external configuration properties in
`+spring.jms.*+`:
[source,properties,indent=0]
----
spring.jms.cache.session-cache-size=5
----
If you'd rather use native pooling, you can do so by adding a dependency to
`org.apache.activemq:activemq-jms-pool` and configuring the `PooledConnectionFactory` `org.apache.activemq:activemq-jms-pool` and configuring the `PooledConnectionFactory`
accordingly, as shown in the following example: accordingly, as shown in the following example:

Loading…
Cancel
Save