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
This commit is contained in:
Stephane Nicoll
2018-06-07 14:55:01 +02:00
parent 0ef54a79b1
commit 8365d53554
10 changed files with 345 additions and 72 deletions

View File

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

View File

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

View File

@@ -48,10 +48,12 @@ import org.springframework.boot.test.context.runner.ApplicationContextRunner;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.jms.connection.CachingConnectionFactory;
import org.springframework.jms.core.JmsTemplate;
import org.springframework.jms.core.SessionCallback;
import org.springframework.jms.support.destination.DestinationResolver;
import org.springframework.jms.support.destination.DynamicDestinationResolver;
import org.springframework.test.util.ReflectionTestUtils;
import static org.assertj.core.api.Assertions.assertThat;
@@ -70,17 +72,69 @@ public class ArtemisAutoConfigurationTests {
.withConfiguration(AutoConfigurations.of(ArtemisAutoConfiguration.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
public void nativeConnectionFactory() {
this.contextRunner.withUserConfiguration(EmptyConfiguration.class)
.withPropertyValues("spring.artemis.mode:native").run((context) -> {
JmsTemplate jmsTemplate = context.getBean(JmsTemplate.class);
ActiveMQConnectionFactory factory = context
.getBean(ActiveMQConnectionFactory.class);
assertThat(factory).isEqualTo(jmsTemplate.getConnectionFactory());
assertNettyConnectionFactory(factory, "localhost", 61616);
assertThat(factory.getUser()).isNull();
assertThat(factory.getPassword()).isNull();
ConnectionFactory connectionFactory = context
.getBean(ConnectionFactory.class);
assertThat(connectionFactory)
.isEqualTo(jmsTemplate.getConnectionFactory());
ActiveMQConnectionFactory activeMQConnectionFactory = getActiveMQConnectionFactory(
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",
"spring.artemis.host:192.168.1.144", "spring.artemis.port:9876")
.run((context) -> {
ActiveMQConnectionFactory factory = context
.getBean(ActiveMQConnectionFactory.class);
assertNettyConnectionFactory(factory, "192.168.1.144", 9876);
assertNettyConnectionFactory(
getActiveMQConnectionFactory(
context.getBean(ConnectionFactory.class)),
"192.168.1.144", 9876);
});
}
@@ -103,12 +158,17 @@ public class ArtemisAutoConfigurationTests {
"spring.artemis.user:user", "spring.artemis.password:secret")
.run((context) -> {
JmsTemplate jmsTemplate = context.getBean(JmsTemplate.class);
ActiveMQConnectionFactory factory = context
.getBean(ActiveMQConnectionFactory.class);
assertThat(factory).isEqualTo(jmsTemplate.getConnectionFactory());
assertNettyConnectionFactory(factory, "localhost", 61616);
assertThat(factory.getUser()).isEqualTo("user");
assertThat(factory.getPassword()).isEqualTo("secret");
ConnectionFactory connectionFactory = context
.getBean(ConnectionFactory.class);
assertThat(connectionFactory)
.isEqualTo(jmsTemplate.getConnectionFactory());
ActiveMQConnectionFactory activeMQConnectionFactory = getActiveMQConnectionFactory(
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);
assertThat(configuration.isPersistenceEnabled()).isFalse();
assertThat(configuration.isSecurityEnabled()).isFalse();
ActiveMQConnectionFactory factory = context
.getBean(ActiveMQConnectionFactory.class);
assertInVmConnectionFactory(factory);
assertInVmConnectionFactory(getActiveMQConnectionFactory(
context.getBean(ConnectionFactory.class)));
});
}
@@ -142,9 +201,8 @@ public class ArtemisAutoConfigurationTests {
org.apache.activemq.artemis.core.config.Configuration.class);
assertThat(configuration.isPersistenceEnabled()).isFalse();
assertThat(configuration.isSecurityEnabled()).isFalse();
ActiveMQConnectionFactory factory = context
.getBean(ActiveMQConnectionFactory.class);
assertInVmConnectionFactory(factory);
assertInVmConnectionFactory(getActiveMQConnectionFactory(
context.getBean(ConnectionFactory.class)));
});
}
@@ -155,9 +213,10 @@ public class ArtemisAutoConfigurationTests {
.withPropertyValues("spring.artemis.embedded.enabled:false")
.run((context) -> {
assertThat(context).doesNotHaveBean(EmbeddedJMS.class);
ActiveMQConnectionFactory factory = context
.getBean(ActiveMQConnectionFactory.class);
assertNettyConnectionFactory(factory, "localhost", 61616);
assertNettyConnectionFactory(
getActiveMQConnectionFactory(
context.getBean(ConnectionFactory.class)),
"localhost", 61616);
});
}
@@ -169,9 +228,8 @@ public class ArtemisAutoConfigurationTests {
"spring.artemis.embedded.enabled:false")
.run((context) -> {
assertThat(context.getBeansOfType(EmbeddedJMS.class)).isEmpty();
ActiveMQConnectionFactory connectionFactory = context
.getBean(ActiveMQConnectionFactory.class);
assertInVmConnectionFactory(connectionFactory);
assertInVmConnectionFactory(getActiveMQConnectionFactory(
context.getBean(ConnectionFactory.class)));
});
}
@@ -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(
ActiveMQConnectionFactory connectionFactory) {
TransportConfiguration transportConfig = getSingleTransportConfiguration(