欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  IT编程

记一次工作中使用spring-boot-activemq的排错经历

程序员文章站 2022-06-21 13:38:10
一. 问题描述最近在使用新版本的spring boot连接activeMQ时(2.1.1.RELEASE)遇到了一个问题:引入依赖后, org.springframework.boot spring-boot-starter-parent 2.1.1.RELEASE

一. 问题描述

最近在使用新版本的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-activemq的排错经历

但是如果用老版本的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>

本文地址:https://blog.csdn.net/hermi0ne/article/details/107389022

相关标签: 问题 spring boot