1、是springboot 整合 activeMq
查了网上各种出现此错误的解决办法,都是手动创建connectionFactory并创建JmsTemplate相关Bean对象。但是这种方式治标不治本。既然spring boot官方有整合ActiveMQ的相关方法,不可能会要求用户自己手动去创建相关的Bean对象的。此处个人进行了相关的分析并给出了对应解决办法:
通过查看日志(以上截取的有这段日志):
JmsAutoConfiguration:
Did not match:
- @ConditionalOnBean (types: javax.jms.ConnectionFactory; SearchStrategy: all) did not find any beans of type javax.jms.ConnectionFactory (OnBeanCondition)
说明spring 容器中并未有ConnectionFactory相关的bean对象。在往上翻日志会有如下几段日志:
ActiveMQConnectionFactoryConfiguration.PooledConnectionFactoryConfiguration:
Did not match:
- @ConditionalOnClass did not find required class ‘org.messaginghub.pooled.jms.JmsPoolConnectionFactory’ (OnClassCondition)
ActiveMQConnectionFactoryConfiguration.SimpleConnectionFactoryConfiguration:
Did not match:
- @ConditionalOnProperty (spring.activemq.pool.enabled=false) found different value in property ‘enabled’ (OnPropertyCondition)
Matched:
- @ConditionalOnClass found required class ‘org.springframework.jms.connection.CachingConnectionFactory’ (OnClassCondition)
spring boot 要使用PooledConnectionFactoryConfiguration静态内部类需要类路径下存在org.messaginghub.pooled.jms.JmsPoolConnectionFactory类。
我这里截取了PooledConnectionFactoryConfiguration相关的源码:
@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<ActiveMQConnectionFactoryCustomizer> factoryCustomizers) {
ActiveMQConnectionFactory connectionFactory = new ActiveMQConnectionFactoryFactory(
properties,
factoryCustomizers.orderedStream().collect(Collectors.toList()))
.createConnectionFactory(ActiveMQConnectionFactory.class);
return new JmsPoolConnectionFactoryFactory(properties.getPool())
.createPooledConnectionFactory(connectionFactory);
}
}
PooledConnectionFactoryConfiguration这个静态内部类中pooledJmsConnectionFactory方法上标注了@Bean,说明此方法返回的对象会被加入到spring容器中。而返回的JmsPoolConnectionFactory对象元类实现了ConnectionFactory接口。所以此静态内部类便是出现问题的源头。
由于spring boot自动配置该内部类的条件是类路径下必须存在JmsPoolConnectionFactory和PooledObject两个类。
查看了依赖包中并未找到JmsPoolConnectionFactory该类,从日志信息上看到该类应该存放于org.messaginghub.pooled.jms包下的。但是我们依赖中并未引入相关的依赖包。从maven中央仓库中查询了该包的前缀org.messaginghub发现该依赖是在PooledJMS Library下的。然后尝试引入该maven依赖并去掉原来的ActiveMQ Pool依赖:
重新启动spring boot 应用后,问题解决了。
spring boot 2.1.*中引入了CachingConnectionFactory,所以在application.properties可以使用spring.jms.cache.**相关的配置。
查看spring boot 2.1.*和spring boot 2.0.*整合ActiveMQ时需要的重要类ActiveMQConnectionFactoryConfiguration源码:
//spring boot 2.1.*版本的源码如下
@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<ActiveMQConnectionFactoryCustomizer> connectionFactoryCustomizers;
SimpleConnectionFactoryConfiguration(JmsProperties jmsProperties,
ActiveMQProperties properties,
ObjectProvider<ActiveMQConnectionFactoryCustomizer> 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<ActiveMQConnectionFactoryCustomizer> factoryCustomizers) {
ActiveMQConnectionFactory connectionFactory = new ActiveMQConnectionFactoryFactory(
properties,
factoryCustomizers.orderedStream().collect(Collectors.toList()))
.createConnectionFactory(ActiveMQConnectionFactory.class);
return new JmsPoolConnectionFactoryFactory(properties.getPool())
.createPooledConnectionFactory(connectionFactory);
}
}
}
//spring 2.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<List<ActiveMQConnectionFactoryCustomizer>> 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)
public PooledConnectionFactory pooledJmsConnectionFactory(
ActiveMQProperties properties,
ObjectProvider<List<ActiveMQConnectionFactoryCustomizer>> factoryCustomizers) {
PooledConnectionFactory pooledConnectionFactory = new PooledConnectionFactory(
new ActiveMQConnectionFactoryFactory(properties,
factoryCustomizers.getIfAvailable()).createConnectionFactory(
ActiveMQConnectionFactory.class));
ActiveMQProperties.Pool pool = properties.getPool();
pooledConnectionFactory.setBlockIfSessionPoolIsFull(pool.isBlockIfFull());
if (pool.getBlockIfFullTimeout() != null) {
pooledConnectionFactory.setBlockIfSessionPoolIsFullTimeout(
pool.getBlockIfFullTimeout().toMillis());
}
pooledConnectionFactory
.setCreateConnectionOnStartup(pool.isCreateConnectionOnStartup());
if (pool.getExpiryTimeout() != null) {
pooledConnectionFactory
.setExpiryTimeout(pool.getExpiryTimeout().toMillis());
}
if (pool.getIdleTimeout() != null) {
pooledConnectionFactory
.setIdleTimeout((int) pool.getIdleTimeout().toMillis());
}
pooledConnectionFactory.setMaxConnections(pool.getMaxConnections());
pooledConnectionFactory.setMaximumActiveSessionPerConnection(
pool.getMaximumActiveSessionPerConnection());
pooledConnectionFactory
.setReconnectOnException(pool.isReconnectOnException());
if (pool.getTimeBetweenExpirationCheck() != null) {
pooledConnectionFactory.setTimeBetweenExpirationCheckMillis(
pool.getTimeBetweenExpirationCheck().toMillis());
}
pooledConnectionFactory
.setUseAnonymousProducers(pool.isUseAnonymousProducers());
return pooledConnectionFactory;
}
}
}
springboot 2.1.*需要使用JmsPoolConnectionFactory和PooledObject,而2.0.*则是直接使用PooledConnectionFactory。2.1.*增加了JMS缓存连接工厂,默认采用的连接池不再是activeMQ的连接池,而是采用了PooledJMS Library。当配置spring.activemq.pool.enabled为true时使用的是JmsPoolConnectionFactoryProperties而不是Pool。相比2.0.*代码有较大的改动。