mirror of
https://github.com/spring-projects/spring-boot.git
synced 2024-09-03 04:26:12 +08:00
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 bedf2edf
.
Closes gh-4748
This commit is contained in:
parent
474ffa717e
commit
7d5cc3da63
@ -16,18 +16,16 @@
|
|||||||
|
|
||||||
package org.springframework.boot.autoconfigure.jms.activemq;
|
package org.springframework.boot.autoconfigure.jms.activemq;
|
||||||
|
|
||||||
import java.lang.reflect.Method;
|
|
||||||
|
|
||||||
import javax.jms.ConnectionFactory;
|
import javax.jms.ConnectionFactory;
|
||||||
|
|
||||||
import org.apache.activemq.ActiveMQConnectionFactory;
|
import org.apache.activemq.ActiveMQConnectionFactory;
|
||||||
import org.apache.activemq.pool.PooledConnectionFactory;
|
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.ConditionalOnMissingBean;
|
||||||
|
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
|
||||||
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.util.Assert;
|
|
||||||
import org.springframework.util.ReflectionUtils;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Configuration for ActiveMQ {@link ConnectionFactory}.
|
* Configuration for ActiveMQ {@link ConnectionFactory}.
|
||||||
@ -43,31 +41,24 @@ import org.springframework.util.ReflectionUtils;
|
|||||||
class ActiveMQConnectionFactoryConfiguration {
|
class ActiveMQConnectionFactoryConfiguration {
|
||||||
|
|
||||||
@Bean
|
@Bean
|
||||||
public ConnectionFactory jmsConnectionFactory(ActiveMQProperties properties) {
|
@ConditionalOnProperty(prefix = "spring.activemq", name = "pooled", havingValue = "false", matchIfMissing = true)
|
||||||
ActiveMQConnectionFactory connectionFactory = new ActiveMQConnectionFactoryFactory(
|
public ActiveMQConnectionFactory jmsConnectionFactory(ActiveMQProperties properties) {
|
||||||
properties).createConnectionFactory(ActiveMQConnectionFactory.class);
|
return new ActiveMQConnectionFactoryFactory(properties)
|
||||||
if (properties.isPooled()) {
|
.createConnectionFactory(ActiveMQConnectionFactory.class);
|
||||||
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;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private Method findConnectionFactorySetter() {
|
@ConditionalOnClass(PooledConnectionFactory.class)
|
||||||
Method setter = findConnectionFactorySetter(ConnectionFactory.class);
|
static class PooledConnectionFactoryConfiguration {
|
||||||
if (setter == null) {
|
|
||||||
setter = findConnectionFactorySetter(Object.class);
|
@Bean(destroyMethod = "stop")
|
||||||
}
|
@ConditionalOnProperty(prefix = "spring.activemq", name = "pooled", havingValue = "true", matchIfMissing = false)
|
||||||
return setter;
|
public PooledConnectionFactory pooledJmsConnectionFactory(
|
||||||
|
ActiveMQProperties properties) {
|
||||||
|
return new PooledConnectionFactory(
|
||||||
|
new ActiveMQConnectionFactoryFactory(properties)
|
||||||
|
.createConnectionFactory(ActiveMQConnectionFactory.class));
|
||||||
}
|
}
|
||||||
|
|
||||||
private Method findConnectionFactorySetter(Class<?> param) {
|
|
||||||
return ReflectionUtils.findMethod(PooledConnectionFactory.class,
|
|
||||||
"setConnectionFactory", param);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -26,6 +26,7 @@ import org.apache.activemq.pool.PooledConnectionFactory;
|
|||||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnBean;
|
import org.springframework.boot.autoconfigure.condition.ConditionalOnBean;
|
||||||
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.jta.XAConnectionFactoryWrapper;
|
import org.springframework.boot.jta.XAConnectionFactoryWrapper;
|
||||||
import org.springframework.context.annotation.Bean;
|
import org.springframework.context.annotation.Bean;
|
||||||
import org.springframework.context.annotation.Configuration;
|
import org.springframework.context.annotation.Configuration;
|
||||||
@ -53,15 +54,25 @@ class ActiveMQXAConnectionFactoryConfiguration {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Bean
|
@Bean
|
||||||
public ConnectionFactory nonXaJmsConnectionFactory(ActiveMQProperties properties) {
|
@ConditionalOnProperty(prefix = "spring.activemq", name = "pooled", havingValue = "false", matchIfMissing = true)
|
||||||
ActiveMQConnectionFactory connectionFactory = new ActiveMQConnectionFactoryFactory(
|
public ActiveMQConnectionFactory nonXaJmsConnectionFactory(
|
||||||
properties).createConnectionFactory(ActiveMQConnectionFactory.class);
|
ActiveMQProperties properties) {
|
||||||
if (properties.isPooled()) {
|
return new ActiveMQConnectionFactoryFactory(properties)
|
||||||
PooledConnectionFactory pool = new PooledConnectionFactory();
|
.createConnectionFactory(ActiveMQConnectionFactory.class);
|
||||||
pool.setConnectionFactory(connectionFactory);
|
|
||||||
return pool;
|
|
||||||
}
|
}
|
||||||
return connectionFactory;
|
|
||||||
|
@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));
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -17,6 +17,7 @@
|
|||||||
package org.springframework.boot.autoconfigure.jms.activemq;
|
package org.springframework.boot.autoconfigure.jms.activemq;
|
||||||
|
|
||||||
import javax.jms.ConnectionFactory;
|
import javax.jms.ConnectionFactory;
|
||||||
|
import javax.jms.JMSException;
|
||||||
|
|
||||||
import org.apache.activemq.ActiveMQConnectionFactory;
|
import org.apache.activemq.ActiveMQConnectionFactory;
|
||||||
import org.apache.activemq.pool.PooledConnectionFactory;
|
import org.apache.activemq.pool.PooledConnectionFactory;
|
||||||
@ -29,6 +30,8 @@ import org.springframework.context.annotation.Bean;
|
|||||||
import org.springframework.context.annotation.Configuration;
|
import org.springframework.context.annotation.Configuration;
|
||||||
|
|
||||||
import static org.hamcrest.Matchers.instanceOf;
|
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.assertEquals;
|
||||||
import static org.junit.Assert.assertThat;
|
import static org.junit.Assert.assertThat;
|
||||||
import static org.junit.Assert.assertTrue;
|
import static org.junit.Assert.assertTrue;
|
||||||
@ -62,11 +65,14 @@ public class ActiveMQAutoConfigurationTests {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void pooledConnectionFactoryConfiguration() {
|
public void pooledConnectionFactoryConfiguration() throws JMSException {
|
||||||
load(EmptyConfiguration.class, "spring.activemq.pooled:true");
|
load(EmptyConfiguration.class, "spring.activemq.pooled:true");
|
||||||
ConnectionFactory connectionFactory = this.context
|
ConnectionFactory connectionFactory = this.context
|
||||||
.getBean(ConnectionFactory.class);
|
.getBean(ConnectionFactory.class);
|
||||||
assertThat(connectionFactory, instanceOf(PooledConnectionFactory.class));
|
assertThat(connectionFactory, instanceOf(PooledConnectionFactory.class));
|
||||||
|
this.context.close();
|
||||||
|
assertThat(((PooledConnectionFactory) connectionFactory).createConnection(),
|
||||||
|
is(nullValue()));
|
||||||
}
|
}
|
||||||
|
|
||||||
private void load(Class<?> config, String... environment) {
|
private void load(Class<?> config, String... environment) {
|
||||||
|
Loading…
Reference in New Issue
Block a user