記一次工作中使用spring-boot-activemq的排錯經歷
一. 問題描述
最近在使用新版本的spring boot連線activeMQ時(2.1.1.RELEASE)遇到了一個問題:引入依賴後,
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.1.1.RELEASE</version>
<relativePath/>
</parent>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-activemq</artifactId>
</dependency>
<dependency>
<groupId>org.apache.activemq</groupId>
<artifactId>activemq-pool</artifactId>
</dependency>
</dependencies>
如果開啟activemq的連線池,則 JmsTemplate 就無法自動注入進來,如下所示:
但是如果用老版本的spring boot(1.5.13.RELEASE),同樣的配置下則沒有這個問題。
經過分析原始碼,終於找到了這個問題的答案,原因如下所示:
二. 原因
對spring boot activemq的配置:
spring.activemq.broker-url=failover:(tcp://ip1:port1,tcp://ip2:port2)?nested.wireFormat.maxInactivityDuration=1000
spring.activemq.in-memory=false
# true表示使用連線池
spring.activemq.pool.enabled=true
# 連線池的最大連線數
spring.activemq.pool.max-connections=5
# 空閒的連線過期時間,預設為30s
spring.activemq.pool.idle-timeout=30000
在2.1.1版本中:
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<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.activemq.pool.enabled=true" 時,會使用 JmsPoolConnectionFactory,但是這個類(org.messaginghub.pooled.jms.JmsPoolConnectionFactory)並不在activemq-pool這個依賴中,所以導致ConnectionFactory無法注入,因此 JmsTemplate也就無法由Spring容器來管理。因此需要引入別的依賴,如下所示:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-activemq</artifactId>
</dependency>
<dependency>
<groupId>org.messaginghub</groupId>
<artifactId>pooled-jms</artifactId>
</dependency>
而在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<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)
@ConfigurationProperties(prefix = "spring.activemq.pool.configuration")
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());
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:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-activemq</artifactId>
</dependency>
<dependency>
<groupId>org.apache.activemq</groupId>
<artifactId>activemq-pool</artifactId>
</dependency>
相關文章
- 記一次靈異般的 Bug 除錯經歷除錯
- L02-8.2 筆記 記一次查錯經歷筆記
- 記一次面試經歷面試
- 記一次 Google 面試經歷Go面試
- 記錄一次WhatTheFuck經歷
- 記一次使用策略模式優化程式碼的經歷模式優化
- 記錄一次微信分享的經歷
- 記一次編譯GCC的經歷編譯GC
- 記一次翻譯站經歷
- 記一次 jQuery 踩坑經歷jQuery
- 記一次效能優化經歷優化
- 記一次我的 MySQL 調優經歷MySql
- 記錄一次破解xjar加密的經歷JAR加密
- 記錄一次Mongodb被勒索的經歷MongoDB
- 記一次詭異的故障排查經歷
- 記一次面試後的經歷,求解篇面試
- 記一次封裝Axios的經歷封裝iOS
- 記一次laravel中使用jquery ajax上傳FormData資料時報錯解決經歷LaraveljQueryORM
- 記一次遠端協助的排錯案例
- 記一次 Vagrant 排坑經歷:error: Raw-mode is unavailable courtesy of Hyper-VErrorAI
- 記一次 CDN 流量被盜刷經歷
- 記一次慘敗的Oracle DBA面試經歷Oracle面試
- 記一次真實的webpack優化經歷Web優化
- 記一次真實的網站被黑經歷網站
- 記一次有點抽象的滲透經歷抽象
- 記一次網站被攻擊經歷網站
- 記一次從刪庫到恢復的經歷
- 記錄一次AndroidStudio導OkHttp的經歷AndroidHTTP
- 記CTF小白的第一次刷題經歷
- 使用執行緒執行框架的一次經歷執行緒框架
- 記一次preact遷移到react16.6.7的經歷React
- 記錄一次成都阿里一面的經歷阿里
- 記一次element-ui元件開發經歷UI元件
- 記一次fis3+react開發經歷S3React
- 記一次 Laravel 應用效能調優經歷Laravel
- 記一次被“虐的體無完膚”的面試經歷面試
- 一次java面試經歷Java面試
- 記一次協助排查許可權問題的經歷