Skip to content

Enable Redis connection pool if commons-pool2 is on the classpath #26326

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
wants to merge 7 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright 2012-2020 the original author or authors.
* Copyright 2012-2021 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
Expand Down Expand Up @@ -41,6 +41,7 @@
*
* @author Mark Paluch
* @author Stephane Nicoll
* @author Weix Sun
*/
@Configuration(proxyBeanMethods = false)
@ConditionalOnClass({ GenericObjectPool.class, JedisConnection.class, Jedis.class })
Expand Down Expand Up @@ -76,7 +77,7 @@ private JedisClientConfiguration getJedisClientConfiguration(
ObjectProvider<JedisClientConfigurationBuilderCustomizer> builderCustomizers) {
JedisClientConfigurationBuilder builder = applyProperties(JedisClientConfiguration.builder());
RedisProperties.Pool pool = getProperties().getJedis().getPool();
if (pool != null) {
if (pool.getEnabled()) {
applyPooling(pool, builder);
}
if (StringUtils.hasText(getProperties().getUrl())) {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright 2012-2020 the original author or authors.
* Copyright 2012-2021 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
Expand Down Expand Up @@ -44,19 +44,24 @@
import org.springframework.data.redis.connection.lettuce.LettuceClientConfiguration.LettuceClientConfigurationBuilder;
import org.springframework.data.redis.connection.lettuce.LettuceConnectionFactory;
import org.springframework.data.redis.connection.lettuce.LettucePoolingClientConfiguration;
import org.springframework.util.ClassUtils;
import org.springframework.util.StringUtils;

/**
* Redis connection configuration using Lettuce.
*
* @author Mark Paluch
* @author Andy Wilkinson
* @author Weix Sun
*/
@Configuration(proxyBeanMethods = false)
@ConditionalOnClass(RedisClient.class)
@ConditionalOnProperty(name = "spring.redis.client-type", havingValue = "lettuce", matchIfMissing = true)
class LettuceConnectionConfiguration extends RedisConnectionConfiguration {

private static final boolean POOl2_IS_PRESENT = ClassUtils
.isPresent(PoolBuilderFactory.GENERIC_OBJECT_POOL_CONFIG_CLASS_NAME, null);

LettuceConnectionConfiguration(RedisProperties properties,
ObjectProvider<RedisSentinelConfiguration> sentinelConfigurationProvider,
ObjectProvider<RedisClusterConfiguration> clusterConfigurationProvider) {
Expand Down Expand Up @@ -104,10 +109,13 @@ private LettuceClientConfiguration getLettuceClientConfiguration(
}

private LettuceClientConfigurationBuilder createBuilder(Pool pool) {
if (pool == null) {
return LettuceClientConfiguration.builder();
if (POOl2_IS_PRESENT) {
if (pool.getEnabled() != null && !pool.getEnabled()) {
return LettuceClientConfiguration.builder();
}
return new PoolBuilderFactory().createBuilder(pool);
}
return new PoolBuilderFactory().createBuilder(pool);
return LettuceClientConfiguration.builder();
}

private LettuceClientConfigurationBuilder applyProperties(
Expand Down Expand Up @@ -168,6 +176,8 @@ private void customizeConfigurationFromUrl(LettuceClientConfiguration.LettuceCli
*/
private static class PoolBuilderFactory {

private static final String GENERIC_OBJECT_POOL_CONFIG_CLASS_NAME = "org.apache.commons.pool2.impl.GenericObjectPoolConfig";

LettuceClientConfigurationBuilder createBuilder(Pool properties) {
return LettucePoolingClientConfiguration.builder().poolConfig(getPoolConfig(properties));
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright 2012-2020 the original author or authors.
* Copyright 2012-2021 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
Expand Down Expand Up @@ -233,6 +233,8 @@ public enum ClientType {
*/
public static class Pool {

private Boolean enabled;

/**
* Maximum number of "idle" connections in the pool. Use a negative value to
* indicate an unlimited number of idle connections.
Expand Down Expand Up @@ -265,6 +267,14 @@ public static class Pool {
*/
private Duration timeBetweenEvictionRuns;

public Boolean getEnabled() {
return this.enabled;
}

public void setEnabled(Boolean enabled) {
this.enabled = enabled;
}

public int getMaxIdle() {
return this.maxIdle;
}
Expand Down Expand Up @@ -396,14 +406,16 @@ public static class Jedis {
/**
* Jedis pool configuration.
*/
private Pool pool;
private final Pool pool;

public Pool getPool() {
return this.pool;
public Jedis() {
Pool pool = new Pool();
pool.setEnabled(true);
this.pool = pool;
}

public void setPool(Pool pool) {
this.pool = pool;
public Pool getPool() {
return this.pool;
}

}
Expand All @@ -421,7 +433,7 @@ public static class Lettuce {
/**
* Lettuce pool configuration.
*/
private Pool pool;
private final Pool pool = new Pool();

private final Cluster cluster = new Cluster();

Expand All @@ -437,10 +449,6 @@ public Pool getPool() {
return this.pool;
}

public void setPool(Pool pool) {
this.pool = pool;
}

public Cluster getCluster() {
return this.cluster;
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright 2012-2020 the original author or authors.
* Copyright 2012-2021 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
Expand Down Expand Up @@ -37,6 +37,7 @@
*
* @author Mark Paluch
* @author Stephane Nicoll
* @author Weix Sun
*/
@ClassPathExclusions("lettuce-core-*.jar")
class RedisAutoConfigurationJedisTests {
Expand Down Expand Up @@ -143,6 +144,16 @@ void testRedisConfigurationWithPool() {
});
}

@Test
void testRedisConfigurationDisabledPool() {
this.contextRunner.withPropertyValues("spring.redis.host:foo", "spring.redis.jedis.pool.enabled:false")
.run((context) -> {
JedisConnectionFactory cf = context.getBean(JedisConnectionFactory.class);
assertThat(cf.getHostName()).isEqualTo("foo");
assertThat(cf.getClientConfiguration().isUsePooling()).isEqualTo(false);
});
}

@Test
void testRedisConfigurationWithTimeoutAndConnectTimeout() {
this.contextRunner.withPropertyValues("spring.redis.host:foo", "spring.redis.timeout:250",
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright 2012-2020 the original author or authors.
* Copyright 2012-2021 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
Expand Down Expand Up @@ -65,6 +65,7 @@
* @author Stephane Nicoll
* @author Alen Turkovic
* @author Scott Frederick
* @author Weix Sun
*/
class RedisAutoConfigurationTests {

Expand Down Expand Up @@ -155,10 +156,24 @@ void testPasswordInUrlStartsWithColon() {
}

@Test
void testRedisConfigurationWithPool() {
this.contextRunner.withPropertyValues("spring.redis.host:foo", "spring.redis.lettuce.pool.min-idle:1",
"spring.redis.lettuce.pool.max-idle:4", "spring.redis.lettuce.pool.max-active:16",
"spring.redis.lettuce.pool.max-wait:2000", "spring.redis.lettuce.pool.time-between-eviction-runs:30000",
void testEnableConnectionPoolWhenCommons_pool2OnTheClasspath() {
this.contextRunner.withPropertyValues("spring.redis.host:foo").run((context) -> {
LettuceConnectionFactory cf = context.getBean(LettuceConnectionFactory.class);
assertThat(cf.getHostName()).isEqualTo("foo");
GenericObjectPoolConfig<?> poolConfig = getPoolingClientConfiguration(cf).getPoolConfig();
assertThat(poolConfig.getMinIdle()).isEqualTo(0);
assertThat(poolConfig.getMaxIdle()).isEqualTo(8);
assertThat(poolConfig.getMaxTotal()).isEqualTo(8);
assertThat(poolConfig.getMaxWaitMillis()).isEqualTo(-1);
});
}

@Test
void testRedisConfigurationWithPoolUsingCustomValue() {
this.contextRunner.withPropertyValues("spring.redis.host:foo", "spring.redis.lettuce.pool.enabled:true",
"spring.redis.lettuce.pool.min-idle:1", "spring.redis.lettuce.pool.max-idle:4",
"spring.redis.lettuce.pool.max-active:16", "spring.redis.lettuce.pool.max-wait:2000",
"spring.redis.lettuce.pool.time-between-eviction-runs:30000",
"spring.redis.lettuce.shutdown-timeout:1000").run((context) -> {
LettuceConnectionFactory cf = context.getBean(LettuceConnectionFactory.class);
assertThat(cf.getHostName()).isEqualTo("foo");
Expand All @@ -172,6 +187,17 @@ void testRedisConfigurationWithPool() {
});
}

@Test
void testRedisConfigurationDisabledPool() {
this.contextRunner.withPropertyValues("spring.redis.host:foo", "spring.redis.lettuce.pool.enabled:false")
.run((context) -> {
LettuceConnectionFactory cf = context.getBean(LettuceConnectionFactory.class);
assertThat(cf.getHostName()).isEqualTo("foo");
assertThat(ReflectionTestUtils.getField(cf, "clientConfiguration"))
.isNotInstanceOf(LettucePoolingClientConfiguration.class);
});
}

@Test
void testRedisConfigurationWithTimeoutAndConnectTimeout() {
this.contextRunner.withPropertyValues("spring.redis.host:foo", "spring.redis.timeout:250",
Expand Down