一. 问题描述
最近在使用新版本的spring boot连接activeMQ时(2.1.1.RELEASE)遇到了一个问题:引入依赖后
org.springframework.boot
spring-boot-starter-parent
2.1.1.RELEASE
org.springframework.boot
spring-boot-starter-activemq
org.apache.activemq
activemq-pool
如果开启activemq的连接池,则 JmsTemplate 就无法自动注入进来,如下所示:
但是如果用老版本的spring boot(1.5.13.RELEASE),同样的配置下则没有这个问题。
经过分析源码,终于找到了这个问题的答案
二. 原因
对spring boot activemq的配置
activemq:
# 连接用户名
user: admin
# 连接密码
password: admin
# mq broker地址
broker-url: tcp://192.168.1.49:61616
pool:
#启用连接池
enabled: true
#连接池最大连接数
max-connections: 20
#空闲的连接过期时间,默认为30秒
idle-timeout: 30000
在2.X版本中:
package org.springframework.boot.autoconfigure.jms.activemq;
import org.messaginghub.pooled.jms.JmsPoolConnectionFactory;
/**
* Configuration for ActiveMQ {@link ConnectionFactory}.
*
* @author Greg Turnquist
* @author Stephane Nicoll
* @author Phillip Webb
* @author Andy Wilkinson
* @author Aurélien Leboulanger
* @since 1.1.0
*/
@Configuration
@ConditionalOnMissingBean(ConnectionFactory.class)
class ActiveMQConnectionFactoryConfiguration {
@Configuration
@ConditionalOnClass(CachingConnectionFactory.class)
@ConditionalOnProperty(prefix = "spring.activemq.pool", name = "enabled", havingValue = "false", matchIfMissing = true)
static class SimpleConnectionFactoryConfiguration {
private final JmsProperties jmsProperties;
private final ActiveMQProperties properties;
private final List connectionFactoryCustomizers;
SimpleConnectionFactoryConfiguration(JmsProperties jmsProperties,
ActiveMQProperties properties,
ObjectProvider connectionFactoryCustomizers) {
this.jmsProperties = jmsProperties;
this.properties = properties;
this.connectionFactoryCustomizers = connectionFactoryCustomizers
.orderedStream().collect(Collectors.toList());
}
@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);
}
}
@Configuration
@ConditionalOnClass({ JmsPoolConnectionFactory.class, PooledObject.class })
static class PooledConnectionFactoryConfiguration {
@Bean(destroyMethod = "stop")
@ConditionalOnProperty(prefix = "spring.activemq.pool", name = "enabled", havingValue = "true", matchIfMissing = false)
public JmsPoolConnectionFactory pooledJmsConnectionFactory(
ActiveMQProperties properties,
ObjectProvider factoryCustomizers) {
ActiveMQConnectionFactory connectionFactory = new ActiveMQConnectionFactoryFactory(
properties,
factoryCustomizers.orderedStream().collect(Collectors.toList()))
.createConnectionFactory(ActiveMQConnectionFactory.class);
return new JmsPoolConnectionFactoryFactory(properties.getPool())
.createPooledConnectionFactory(connectionFactory);
}
}
}
由以上代码可知,当配置文件中存在 "spring.activemq.pool.enabled=true" 时,会使用 JmsPoolConnectionFactory,但是这个类(org.messaginghub.pooled.jms.JmsPoolConnectionFactory)并不在activemq-pool这个依赖中,所以导致ConnectionFactory无法注入,因此 JmsTemplate也就无法由Spring容器来管理。因此需要引入别的依赖,如下所示:
org.springframework.boot
spring-boot-starter-activemq
org.messaginghub
pooled-jms
而在1.5.13版本中
package org.springframework.boot.autoconfigure.jms.activemq;
import org.apache.activemq.pool.PooledConnectionFactory;
/**
* Configuration for ActiveMQ {@link ConnectionFactory}.
*
* @author Greg Turnquist
* @author Stephane Nicoll
* @author Phillip Webb
* @author Andy Wilkinson
* @author Aurélien Leboulanger
* @since 1.1.0
*/
@Configuration
@ConditionalOnMissingBean(ConnectionFactory.class)
class ActiveMQConnectionFactoryConfiguration {
@Bean
@ConditionalOnProperty(prefix = "spring.activemq.pool", name = "enabled", havingValue = "false", matchIfMissing = true)
public ActiveMQConnectionFactory jmsConnectionFactory(ActiveMQProperties properties,
ObjectProvider> factoryCustomizers) {
return new ActiveMQConnectionFactoryFactory(properties,
factoryCustomizers.getIfAvailable())
.createConnectionFactory(ActiveMQConnectionFactory.class);
}
@Configuration
@ConditionalOnClass(PooledConnectionFactory.class)
static class PooledConnectionFactoryConfiguration {
@Bean(destroyMethod = "stop")
@ConditionalOnProperty(prefix = "spring.activemq.pool", name = "enabled", havingValue = "true", matchIfMissing = false)
@ConfigurationProperties(prefix = "spring.activemq.pool.configuration")
public PooledConnectionFactory pooledJmsConnectionFactory(
ActiveMQProperties properties,
ObjectProvider> factoryCustomizers) {
PooledConnectionFactory pooledConnectionFactory = new PooledConnectionFactory(
new ActiveMQConnectionFactoryFactory(properties,
factoryCustomizers.getIfAvailable()).createConnectionFactory(
ActiveMQConnectionFactory.class));
ActiveMQProperties.Pool pool = properties.getPool();
pooledConnectionFactory.setBlockIfSessionPoolIsFull(pool.isBlockIfFull());
pooledConnectionFactory
.setBlockIfSessionPoolIsFullTimeout(pool.getBlockIfFullTimeout());
pooledConnectionFactory
.setCreateConnectionOnStartup(pool.isCreateConnectionOnStartup());
pooledConnectionFactory.setExpiryTimeout(pool.getExpiryTimeout());
pooledConnectionFactory.setIdleTimeout(pool.getIdleTimeout());
pooledConnectionFactory.setMaxConnections(pool.getMaxConnections());
pooledConnectionFactory.setMaximumActiveSessionPerConnection(
pool.getMaximumActiveSessionPerConnection());
pooledConnectionFactory
.setReconnectOnException(pool.isReconnectOnException());
pooledConnectionFactory.setTimeBetweenExpirationCheckMillis(
pool.getTimeBetweenExpirationCheck());
pooledConnectionFactory
.setUseAnonymousProducers(pool.isUseAnonymousProducers());
return pooledConnectionFactory;
}
}
}
当 "spring.activemq.pool.enabled=true" 这个配置项存在时,往spring容器中注入的是 PooledConnectionFactory 这个类,而这个类,在activemq-pool这个依赖中,因此,在1.5.13的版本中,可以依赖activemq-pool。