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 ff47497500..91331a5e9d 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-2019 the original author or authors. + * Copyright 2012-2020 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. @@ -26,6 +26,7 @@ import redis.clients.jedis.JedisPoolConfig; import org.springframework.beans.factory.ObjectProvider; import org.springframework.boot.autoconfigure.condition.ConditionalOnClass; import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; +import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.data.redis.connection.RedisClusterConfiguration; @@ -45,6 +46,8 @@ import org.springframework.util.StringUtils; */ @Configuration(proxyBeanMethods = false) @ConditionalOnClass({ GenericObjectPool.class, JedisConnection.class, Jedis.class }) +@ConditionalOnMissingBean(RedisConnectionFactory.class) +@ConditionalOnProperty(name = "spring.redis.client-type", havingValue = "jedis", matchIfMissing = true) class JedisConnectionConfiguration extends RedisConnectionConfiguration { JedisConnectionConfiguration(RedisProperties properties, @@ -54,7 +57,6 @@ class JedisConnectionConfiguration extends RedisConnectionConfiguration { } @Bean - @ConditionalOnMissingBean(RedisConnectionFactory.class) JedisConnectionFactory redisConnectionFactory( ObjectProvider builderCustomizers) throws UnknownHostException { return createJedisConnectionFactory(builderCustomizers); 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 dca260f473..f49acdbfe9 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 @@ -31,6 +31,7 @@ import org.apache.commons.pool2.impl.GenericObjectPoolConfig; import org.springframework.beans.factory.ObjectProvider; import org.springframework.boot.autoconfigure.condition.ConditionalOnClass; import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; +import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; import org.springframework.boot.autoconfigure.data.redis.RedisProperties.Lettuce.Cluster.Refresh; import org.springframework.boot.autoconfigure.data.redis.RedisProperties.Pool; import org.springframework.context.annotation.Bean; @@ -52,6 +53,7 @@ import org.springframework.util.StringUtils; */ @Configuration(proxyBeanMethods = false) @ConditionalOnClass(RedisClient.class) +@ConditionalOnProperty(name = "spring.redis.client-type", havingValue = "lettuce", matchIfMissing = true) class LettuceConnectionConfiguration extends RedisConnectionConfiguration { LettuceConnectionConfiguration(RedisProperties properties, diff --git a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/data/redis/RedisAutoConfiguration.java b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/data/redis/RedisAutoConfiguration.java index ab7d05f323..9ba9fe5891 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/data/redis/RedisAutoConfiguration.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/data/redis/RedisAutoConfiguration.java @@ -1,5 +1,5 @@ /* - * Copyright 2012-2019 the original author or authors. + * Copyright 2012-2020 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. @@ -21,6 +21,7 @@ import java.net.UnknownHostException; import org.springframework.boot.autoconfigure.EnableAutoConfiguration; import org.springframework.boot.autoconfigure.condition.ConditionalOnClass; import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; +import org.springframework.boot.autoconfigure.condition.ConditionalOnSingleCandidate; import org.springframework.boot.context.properties.EnableConfigurationProperties; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; @@ -52,6 +53,7 @@ public class RedisAutoConfiguration { @Bean @ConditionalOnMissingBean(name = "redisTemplate") + @ConditionalOnSingleCandidate(RedisConnectionFactory.class) public RedisTemplate redisTemplate(RedisConnectionFactory redisConnectionFactory) throws UnknownHostException { RedisTemplate template = new RedisTemplate<>(); @@ -61,6 +63,7 @@ public class RedisAutoConfiguration { @Bean @ConditionalOnMissingBean + @ConditionalOnSingleCandidate(RedisConnectionFactory.class) public StringRedisTemplate stringRedisTemplate(RedisConnectionFactory redisConnectionFactory) throws UnknownHostException { StringRedisTemplate template = new StringRedisTemplate(); 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 c762541a1d..d8c12b6148 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 @@ -76,6 +76,11 @@ public class RedisProperties { */ private String clientName; + /** + * Type of client to use. By default, auto-detected according to the classpath. + */ + private ClientType clientType; + private Sentinel sentinel; private Cluster cluster; @@ -148,6 +153,14 @@ public class RedisProperties { this.clientName = clientName; } + public ClientType getClientType() { + return this.clientType; + } + + public void setClientType(ClientType clientType) { + this.clientType = clientType; + } + public Sentinel getSentinel() { return this.sentinel; } @@ -172,6 +185,23 @@ public class RedisProperties { return this.lettuce; } + /** + * Type of Redis client to use. + */ + public enum ClientType { + + /** + * Use the Lettuce redis client. + */ + LETTUCE, + + /** + * Use the Jedis redis client. + */ + JEDIS + + } + /** * Pool properties. */ 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 9bc153a49f..3e23b540cf 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 @@ -1,5 +1,5 @@ /* - * Copyright 2012-2019 the original author or authors. + * Copyright 2012-2020 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. @@ -25,6 +25,7 @@ import org.springframework.boot.test.context.runner.ApplicationContextRunner; import org.springframework.boot.testsupport.classpath.ClassPathExclusions; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; +import org.springframework.data.redis.connection.RedisConnectionFactory; import org.springframework.data.redis.connection.jedis.JedisClientConfiguration.JedisClientConfigurationBuilder; import org.springframework.data.redis.connection.jedis.JedisConnectionFactory; @@ -42,6 +43,18 @@ class RedisAutoConfigurationJedisTests { private final ApplicationContextRunner contextRunner = new ApplicationContextRunner() .withConfiguration(AutoConfigurations.of(RedisAutoConfiguration.class)); + @Test + void connectionFactoryDefaultsToJedis() { + this.contextRunner.run((context) -> assertThat(context.getBean("redisConnectionFactory")) + .isInstanceOf(JedisConnectionFactory.class)); + } + + @Test + void connectionFactoryIsNotCreatedWhenLettuceIsSelected() { + this.contextRunner.withPropertyValues("spring.redis.client-type=lettuce") + .run((context) -> assertThat(context).doesNotHaveBean(RedisConnectionFactory.class)); + } + @Test void testOverrideRedisConfiguration() { this.contextRunner.withPropertyValues("spring.redis.host:foo", "spring.redis.database:1").run((context) -> { 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 5a1424d21d..7e9a474ab0 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 @@ -37,8 +37,10 @@ import org.springframework.boot.test.context.runner.ContextConsumer; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.data.redis.connection.RedisClusterConfiguration; +import org.springframework.data.redis.connection.RedisConnectionFactory; import org.springframework.data.redis.connection.RedisNode; import org.springframework.data.redis.connection.RedisSentinelConfiguration; +import org.springframework.data.redis.connection.jedis.JedisConnectionFactory; import org.springframework.data.redis.connection.lettuce.LettuceClientConfiguration; import org.springframework.data.redis.connection.lettuce.LettuceClientConfiguration.LettuceClientConfigurationBuilder; import org.springframework.data.redis.connection.lettuce.LettuceConnectionFactory; @@ -72,8 +74,10 @@ class RedisAutoConfigurationTests { @Test void testDefaultRedisConfiguration() { this.contextRunner.run((context) -> { - assertThat(context.getBean("redisTemplate", RedisOperations.class)).isNotNull(); - assertThat(context.getBean(StringRedisTemplate.class)).isNotNull(); + assertThat(context.getBean("redisTemplate")).isInstanceOf(RedisOperations.class); + assertThat(context).hasSingleBean(StringRedisTemplate.class); + assertThat(context).hasSingleBean(RedisConnectionFactory.class); + assertThat(context.getBean(RedisConnectionFactory.class)).isInstanceOf(LettuceConnectionFactory.class); }); } @@ -182,6 +186,22 @@ class RedisAutoConfigurationTests { }); } + @Test + void connectionFactoryWithJedisClientType() { + this.contextRunner.withPropertyValues("spring.redis.client-type:jedis").run((context) -> { + assertThat(context).hasSingleBean(RedisConnectionFactory.class); + assertThat(context.getBean(RedisConnectionFactory.class)).isInstanceOf(JedisConnectionFactory.class); + }); + } + + @Test + void connectionFactoryWithLettuceClientType() { + this.contextRunner.withPropertyValues("spring.redis.client-type:lettuce").run((context) -> { + assertThat(context).hasSingleBean(RedisConnectionFactory.class); + assertThat(context.getBean(RedisConnectionFactory.class)).isInstanceOf(LettuceConnectionFactory.class); + }); + } + @Test void testRedisConfigurationWithSentinel() { List sentinels = Arrays.asList("127.0.0.1:26379", "127.0.0.1:26380");