Skip to content
Permalink
Browse files

Stop ActiveMQ pooled connection factory when context is closed

Previously, ActiveMQ's pooled connection factory was not closed as
part of the application context being closed. This would leave
non-daemon threads running which could cause shutdown to hang unless
the JVM itself was shutting down (in which case a shutdown hook would
stop the pool).

This commit configures each pooled connection factory bean with a
custom destroy method so that the pool is stopped as part of the
application context being closed. To allow the destroy method to only
be declared when the connection factory is pooled, the bean method
has been split into two; one for pooled and one for non-pooled. This
is a partial backport of the changes made in bedf2ed.

Closes gh-4748
  • Loading branch information...
wilkinsona committed Dec 14, 2015
1 parent 474ffa7 commit 7d5cc3da63010a86ae3ad212643d8111a2f370f4
@@ -16,18 +16,16 @@

package org.springframework.boot.autoconfigure.jms.activemq;

import java.lang.reflect.Method;

import javax.jms.ConnectionFactory;

import org.apache.activemq.ActiveMQConnectionFactory;
import org.apache.activemq.pool.PooledConnectionFactory;

import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.util.Assert;
import org.springframework.util.ReflectionUtils;

/**
* Configuration for ActiveMQ {@link ConnectionFactory}.
@@ -43,31 +41,24 @@
class ActiveMQConnectionFactoryConfiguration {

@Bean
public ConnectionFactory jmsConnectionFactory(ActiveMQProperties properties) {
ActiveMQConnectionFactory connectionFactory = new ActiveMQConnectionFactoryFactory(
properties).createConnectionFactory(ActiveMQConnectionFactory.class);
if (properties.isPooled()) {
PooledConnectionFactory pool = new PooledConnectionFactory();
Method setConnectionFactory = findConnectionFactorySetter();
Assert.state(setConnectionFactory != null,
"No supported " + "setConnectionFactory method was found");
ReflectionUtils.invokeMethod(setConnectionFactory, pool, connectionFactory);
return pool;
}
return connectionFactory;
@ConditionalOnProperty(prefix = "spring.activemq", name = "pooled", havingValue = "false", matchIfMissing = true)
public ActiveMQConnectionFactory jmsConnectionFactory(ActiveMQProperties properties) {
return new ActiveMQConnectionFactoryFactory(properties)
.createConnectionFactory(ActiveMQConnectionFactory.class);
}

private Method findConnectionFactorySetter() {
Method setter = findConnectionFactorySetter(ConnectionFactory.class);
if (setter == null) {
setter = findConnectionFactorySetter(Object.class);
@ConditionalOnClass(PooledConnectionFactory.class)
static class PooledConnectionFactoryConfiguration {

@Bean(destroyMethod = "stop")
@ConditionalOnProperty(prefix = "spring.activemq", name = "pooled", havingValue = "true", matchIfMissing = false)
public PooledConnectionFactory pooledJmsConnectionFactory(
ActiveMQProperties properties) {
return new PooledConnectionFactory(
new ActiveMQConnectionFactoryFactory(properties)
.createConnectionFactory(ActiveMQConnectionFactory.class));
}
return setter;
}

private Method findConnectionFactorySetter(Class<?> param) {
return ReflectionUtils.findMethod(PooledConnectionFactory.class,
"setConnectionFactory", param);
}

}
@@ -26,6 +26,7 @@
import org.springframework.boot.autoconfigure.condition.ConditionalOnBean;
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.boot.jta.XAConnectionFactoryWrapper;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@@ -53,15 +54,25 @@ public ConnectionFactory jmsConnectionFactory(ActiveMQProperties properties,
}

@Bean
public ConnectionFactory nonXaJmsConnectionFactory(ActiveMQProperties properties) {
ActiveMQConnectionFactory connectionFactory = new ActiveMQConnectionFactoryFactory(
properties).createConnectionFactory(ActiveMQConnectionFactory.class);
if (properties.isPooled()) {
PooledConnectionFactory pool = new PooledConnectionFactory();
pool.setConnectionFactory(connectionFactory);
return pool;
@ConditionalOnProperty(prefix = "spring.activemq", name = "pooled", havingValue = "false", matchIfMissing = true)
public ActiveMQConnectionFactory nonXaJmsConnectionFactory(
ActiveMQProperties properties) {
return new ActiveMQConnectionFactoryFactory(properties)
.createConnectionFactory(ActiveMQConnectionFactory.class);
}

@ConditionalOnClass(PooledConnectionFactory.class)
@ConditionalOnProperty(prefix = "spring.activemq", name = "pooled", havingValue = "true", matchIfMissing = false)
static class PooledConnectionFactoryConfiguration {

@Bean(destroyMethod = "stop")
public PooledConnectionFactory pooledNonXaJmsConnectionFactory(
ActiveMQProperties properties) {
return new PooledConnectionFactory(
new ActiveMQConnectionFactoryFactory(properties)
.createConnectionFactory(ActiveMQConnectionFactory.class));
}
return connectionFactory;

}

}
@@ -17,6 +17,7 @@
package org.springframework.boot.autoconfigure.jms.activemq;

import javax.jms.ConnectionFactory;
import javax.jms.JMSException;

import org.apache.activemq.ActiveMQConnectionFactory;
import org.apache.activemq.pool.PooledConnectionFactory;
@@ -29,6 +30,8 @@
import org.springframework.context.annotation.Configuration;

import static org.hamcrest.Matchers.instanceOf;
import static org.hamcrest.Matchers.is;
import static org.hamcrest.Matchers.nullValue;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertThat;
import static org.junit.Assert.assertTrue;
@@ -62,11 +65,14 @@ public void configurationBacksOffWhenCustomConnectionFactoryExists() {
}

@Test
public void pooledConnectionFactoryConfiguration() {
public void pooledConnectionFactoryConfiguration() throws JMSException {
load(EmptyConfiguration.class, "spring.activemq.pooled:true");
ConnectionFactory connectionFactory = this.context
.getBean(ConnectionFactory.class);
assertThat(connectionFactory, instanceOf(PooledConnectionFactory.class));
this.context.close();
assertThat(((PooledConnectionFactory) connectionFactory).createConnection(),
is(nullValue()));
}

private void load(Class<?> config, String... environment) {

1 comment on commit 7d5cc3d

@raffian

This comment has been minimized.

Copy link

commented on 7d5cc3d Dec 20, 2015

Checks out on 1.2.8, thanks for addressing this after raising on SO, 👍

Please sign in to comment.
You can’t perform that action at this time.