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

2020-05-30  本文已影响0人  renmen2000

一. 问题描述

最近在使用新版本的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 就无法自动注入进来,如下所示:


2019032009243494.png

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

上一篇 下一篇

猜你喜欢

热点阅读