diff --git a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/data/redis/JedisConnectionConfiguration.java b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/data/redis/JedisConnectionConfiguration.java index 94e5cb0126..62dd4685fc 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/data/redis/JedisConnectionConfiguration.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/data/redis/JedisConnectionConfiguration.java @@ -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. @@ -76,7 +76,7 @@ class JedisConnectionConfiguration extends RedisConnectionConfiguration { ObjectProvider builderCustomizers) { JedisClientConfigurationBuilder builder = applyProperties(JedisClientConfiguration.builder()); RedisProperties.Pool pool = getProperties().getJedis().getPool(); - if (pool != null) { + if (isPoolEnabled(pool)) { applyPooling(pool, builder); } if (StringUtils.hasText(getProperties().getUrl())) { diff --git a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/data/redis/LettuceConnectionConfiguration.java b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/data/redis/LettuceConnectionConfiguration.java index e295f97f49..2496e687d7 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/data/redis/LettuceConnectionConfiguration.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/data/redis/LettuceConnectionConfiguration.java @@ -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. @@ -104,10 +104,10 @@ class LettuceConnectionConfiguration extends RedisConnectionConfiguration { } private LettuceClientConfigurationBuilder createBuilder(Pool pool) { - if (pool == null) { - return LettuceClientConfiguration.builder(); + if (isPoolEnabled(pool)) { + return new PoolBuilderFactory().createBuilder(pool); } - return new PoolBuilderFactory().createBuilder(pool); + return LettuceClientConfiguration.builder(); } private LettuceClientConfigurationBuilder applyProperties( diff --git a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/data/redis/RedisConnectionConfiguration.java b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/data/redis/RedisConnectionConfiguration.java index 15bb5b2415..4940843b8a 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/data/redis/RedisConnectionConfiguration.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/data/redis/RedisConnectionConfiguration.java @@ -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. @@ -22,12 +22,14 @@ import java.util.ArrayList; import java.util.List; import org.springframework.beans.factory.ObjectProvider; +import org.springframework.boot.autoconfigure.data.redis.RedisProperties.Pool; import org.springframework.data.redis.connection.RedisClusterConfiguration; import org.springframework.data.redis.connection.RedisNode; import org.springframework.data.redis.connection.RedisPassword; import org.springframework.data.redis.connection.RedisSentinelConfiguration; import org.springframework.data.redis.connection.RedisStandaloneConfiguration; import org.springframework.util.Assert; +import org.springframework.util.ClassUtils; import org.springframework.util.StringUtils; /** @@ -40,6 +42,9 @@ import org.springframework.util.StringUtils; */ abstract class RedisConnectionConfiguration { + private static final boolean COMMONS_POOL2_AVAILABLE = ClassUtils.isPresent("org.apache.commons.pool2.ObjectPool", + RedisConnectionConfiguration.class.getClassLoader()); + private final RedisProperties properties; private final RedisSentinelConfiguration sentinelConfiguration; @@ -122,6 +127,11 @@ abstract class RedisConnectionConfiguration { return this.properties; } + protected boolean isPoolEnabled(Pool pool) { + Boolean enabled = pool.getEnabled(); + return (enabled != null) ? enabled : COMMONS_POOL2_AVAILABLE; + } + private List createSentinels(RedisProperties.Sentinel sentinel) { List nodes = new ArrayList<>(); for (String node : sentinel.getNodes()) { diff --git a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/data/redis/RedisProperties.java b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/data/redis/RedisProperties.java index 0dfb6474d8..df525d60de 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/data/redis/RedisProperties.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/data/redis/RedisProperties.java @@ -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. @@ -233,6 +233,12 @@ public class RedisProperties { */ public static class Pool { + /** + * Whether to enable the pool. Enabled automatically if "commons-pool2" is + * available. + */ + private Boolean enabled; + /** * Maximum number of "idle" connections in the pool. Use a negative value to * indicate an unlimited number of idle connections. @@ -265,6 +271,14 @@ public class RedisProperties { */ private Duration timeBetweenEvictionRuns; + public Boolean getEnabled() { + return this.enabled; + } + + public void setEnabled(Boolean enabled) { + this.enabled = enabled; + } + public int getMaxIdle() { return this.maxIdle; } @@ -396,16 +410,12 @@ public class RedisProperties { /** * Jedis pool configuration. */ - private Pool pool; + private final Pool pool = new Pool(); public Pool getPool() { return this.pool; } - public void setPool(Pool pool) { - this.pool = pool; - } - } /** @@ -421,7 +431,7 @@ public class RedisProperties { /** * Lettuce pool configuration. */ - private Pool pool; + private final Pool pool = new Pool(); private final Cluster cluster = new Cluster(); @@ -437,10 +447,6 @@ public class RedisProperties { return this.pool; } - public void setPool(Pool pool) { - this.pool = pool; - } - public Cluster getCluster() { return this.cluster; } diff --git a/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/data/redis/RedisAutoConfigurationJedisTests.java b/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/data/redis/RedisAutoConfigurationJedisTests.java index 7686f34808..e42d216fe3 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/data/redis/RedisAutoConfigurationJedisTests.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/data/redis/RedisAutoConfigurationJedisTests.java @@ -36,6 +36,7 @@ import static org.assertj.core.api.Assertions.assertThat; * * @author Mark Paluch * @author Stephane Nicoll + * @author Weix Sun */ @ClassPathExclusions("lettuce-core-*.jar") class RedisAutoConfigurationJedisTests { @@ -142,6 +143,16 @@ class RedisAutoConfigurationJedisTests { }); } + @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", diff --git a/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/data/redis/RedisAutoConfigurationLettuceWithoutCommonsPool2Tests.java b/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/data/redis/RedisAutoConfigurationLettuceWithoutCommonsPool2Tests.java new file mode 100644 index 0000000000..2e8c0d6481 --- /dev/null +++ b/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/data/redis/RedisAutoConfigurationLettuceWithoutCommonsPool2Tests.java @@ -0,0 +1,51 @@ +/* + * 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. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.boot.autoconfigure.data.redis; + +import org.junit.jupiter.api.Test; + +import org.springframework.boot.autoconfigure.AutoConfigurations; +import org.springframework.boot.test.context.runner.ApplicationContextRunner; +import org.springframework.boot.testsupport.classpath.ClassPathExclusions; +import org.springframework.data.redis.connection.lettuce.LettuceConnectionFactory; +import org.springframework.data.redis.connection.lettuce.LettucePoolingClientConfiguration; +import org.springframework.test.util.ReflectionTestUtils; + +import static org.assertj.core.api.Assertions.assertThat; + +/** + * Tests for {@link RedisAutoConfiguration} when commons-pool2 is not on the classpath. + * + * @author Stephane Nicoll + */ +@ClassPathExclusions("commons-pool2-*.jar") +public class RedisAutoConfigurationLettuceWithoutCommonsPool2Tests { + + private final ApplicationContextRunner contextRunner = new ApplicationContextRunner() + .withConfiguration(AutoConfigurations.of(RedisAutoConfiguration.class)); + + @Test + void poolWithoutCommonsPool2IsDisabledByDefault() { + this.contextRunner.withPropertyValues("spring.redis.host:foo").run((context) -> { + LettuceConnectionFactory cf = context.getBean(LettuceConnectionFactory.class); + assertThat(cf.getHostName()).isEqualTo("foo"); + assertThat(ReflectionTestUtils.getField(cf, "clientConfiguration")) + .isNotInstanceOf(LettucePoolingClientConfiguration.class); + }); + } + +} diff --git a/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/data/redis/RedisAutoConfigurationTests.java b/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/data/redis/RedisAutoConfigurationTests.java index 91c2bbc92b..7579e15a88 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/data/redis/RedisAutoConfigurationTests.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/data/redis/RedisAutoConfigurationTests.java @@ -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. @@ -31,6 +31,7 @@ import org.apache.commons.pool2.impl.GenericObjectPoolConfig; import org.junit.jupiter.api.Test; import org.springframework.boot.autoconfigure.AutoConfigurations; +import org.springframework.boot.autoconfigure.data.redis.RedisProperties.Pool; import org.springframework.boot.test.context.assertj.AssertableApplicationContext; import org.springframework.boot.test.context.runner.ApplicationContextRunner; import org.springframework.boot.test.context.runner.ContextConsumer; @@ -65,6 +66,7 @@ import static org.assertj.core.api.Assertions.assertThatIllegalStateException; * @author Stephane Nicoll * @author Alen Turkovic * @author Scott Frederick + * @author Weix Sun */ class RedisAutoConfigurationTests { @@ -155,7 +157,21 @@ class RedisAutoConfigurationTests { } @Test - void testRedisConfigurationWithPool() { + void testRedisConfigurationUsePoolByDefault() { + Pool defaultPool = new RedisProperties().getLettuce().getPool(); + 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(defaultPool.getMinIdle()); + assertThat(poolConfig.getMaxIdle()).isEqualTo(defaultPool.getMaxIdle()); + assertThat(poolConfig.getMaxTotal()).isEqualTo(defaultPool.getMaxActive()); + assertThat(poolConfig.getMaxWaitMillis()).isEqualTo(defaultPool.getMaxWait().toMillis()); + }); + } + + @Test + void testRedisConfigurationWithCustomPoolSettings() { 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", @@ -172,6 +188,17 @@ class RedisAutoConfigurationTests { }); } + @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", diff --git a/spring-boot-project/spring-boot-docs/src/docs/asciidoc/features/nosql.adoc b/spring-boot-project/spring-boot-docs/src/docs/asciidoc/features/nosql.adoc index ff1da00025..7d3fe3b45c 100644 --- a/spring-boot-project/spring-boot-docs/src/docs/asciidoc/features/nosql.adoc +++ b/spring-boot-project/spring-boot-docs/src/docs/asciidoc/features/nosql.adoc @@ -46,7 +46,7 @@ If you use Jedis, `JedisClientConfigurationBuilderCustomizer` is also available. If you add your own `@Bean` of any of the auto-configured types, it replaces the default (except in the case of `RedisTemplate`, when the exclusion is based on the bean name, `redisTemplate`, not its type). -A pooled connection factory is auto-configured if `commons-pool2` is on the classpath and at least one `Pool` option of {spring-boot-autoconfigure-module-code}/data/redis/RedisProperties.java[`RedisProperties`] is set. +By default, a pooled connection factory is auto-configured if `commons-pool2` is on the classpath.