感谢大神:
1.问题简述
版本:springboot版本2.1.17 ,activeMQ我想用连接池,我希望当我把spring.activemq.pool.enabled配置为true时,项目也能启动
配置文件
spring.activemq.broker-url=tcp://localhost:61616
#true 表示使用内置的MQ,false则连接服务器
spring.activemq.in-memory=false
#true表示使用连接池;false时,每发送一条数据创建一个连接
spring.activemq.pool.enabled=true
#连接池最大连接数
spring.activemq.pool.max-connections=10
#空闲的连接过期时间,默认为30秒
spring.activemq.pool.idle-timeout=30000
pom文件:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
<version>2.1.17.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter</artifactId>
<version>2.1.17.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<version>2.1.17.RELEASE</version>
</dependency>
启动项目会报错:
Bean method 'jmsMessagingTemplate' in 'JmsAutoConfiguration.MessagingTemplateConfiguration' not loaded because Ancestor org.springframework.boot.autoconfigure.jms.JmsAutoConfiguration did not match
2.方案
引入包
<dependency>
<groupId>org.messaginghub</groupId>
<artifactId>pooled-jms</artifactId>
<version>1.2.1</version>
</dependency>
3.分析过程
从报错来看问题出在 JmsAutoConfiguration.MessagingTemplateConfiguration 上,那么我们看一下这段代码
@Configuration
@ConditionalOnClass({JmsMessagingTemplate.class})
@Import({JmsAutoConfiguration.JmsTemplateConfiguration.class})
protected static class MessagingTemplateConfiguration {
protected MessagingTemplateConfiguration() {
}
@Bean
@ConditionalOnMissingBean({JmsMessageOperations.class})
@ConditionalOnSingleCandidate(JmsTemplate.class)
public JmsMessagingTemplate jmsMessagingTemplate(JmsTemplate jmsTemplate) {
return new JmsMessagingTemplate(jmsTemplate);
}
}
这段代码中的import注解引入了 内部配置类 JmsTemplateConfiguration,这个类内部的一个bean方法如下
@Bean
@ConditionalOnMissingBean({JmsOperations.class})
@ConditionalOnSingleCandidate(ConnectionFactory.class)
public JmsTemplate jmsTemplate(ConnectionFactory connectionFactory) {
PropertyMapper map = PropertyMapper.get();
JmsTemplate template = new JmsTemplate(connectionFactory);
template.setPubSubDomain(this.properties.isPubSubDomain());
ObjectProvider var10001 = this.destinationResolver;
var10001.getClass();
map.from(var10001::getIfUnique).whenNonNull().to(template::setDestinationResolver);
var10001 = this.messageConverter;
var10001.getClass();
map.from(var10001::getIfUnique).whenNonNull().to(template::setMessageConverter);
this.mapTemplateProperties(this.properties.getTemplate(), template);
return template;
}
这里的ConditionalOnSingleCandidate注解需要有个前提,那就是提前要有个ConnectionFactory实例,当我们配置activeMQ的时候,这个工厂配置类是谁呢,是ActiveMQConnectionFactoryConfiguration,这个里面油两个内部类配置类PooledConnectionFactoryConfiguration和SimpleConnectionFactoryConfiguration,我们只关注前者
@Configuration
@ConditionalOnClass({JmsPoolConnectionFactory.class, PooledObject.class})
static class PooledConnectionFactoryConfiguration {
PooledConnectionFactoryConfiguration() {
}
@Bean(
destroyMethod = "stop"
)
@ConditionalOnProperty(
prefix = "spring.activemq.pool",
name = {"enabled"},
havingValue = "true"
)
public JmsPoolConnectionFactory pooledJmsConnectionFactory(ActiveMQProperties properties, ObjectProvider<ActiveMQConnectionFactoryCustomizer> factoryCustomizers) {
ActiveMQConnectionFactory connectionFactory = (new ActiveMQConnectionFactoryFactory(properties, (List)factoryCustomizers.orderedStream().collect(Collectors.toList()))).createConnectionFactory(ActiveMQConnectionFactory.class);
return (new JmsPoolConnectionFactoryFactory(properties.getPool())).createPooledConnectionFactory(connectionFactory);
}
}
注解@ConditionalOnProperty是我们真正需要注意的,这意味着在我们配置最开始的enable=true时候会实例化JmsPoolConnectionFactory,这时候关键点到了,这个JmsPoolConnectionFactory在哪个包呢,就是方案中的包
@ConditionalOnProperty(
prefix = "spring.activemq.pool",
name = {"enabled"},
havingValue = "true"
)