diff --git a/src/main/asciidoc/reference/redis-cluster.adoc b/src/main/asciidoc/reference/redis-cluster.adoc index e7e467dd4..319becebc 100644 --- a/src/main/asciidoc/reference/redis-cluster.adoc +++ b/src/main/asciidoc/reference/redis-cluster.adoc @@ -56,6 +56,17 @@ public class AppConfig { ---- ==== +[TIP] +==== +`RedisClusterConfiguration` can also be defined via `PropertySource`. + +.Configuration Properties +- `spring.redis.cluster.nodes`: Comma delimited list of host:port pairs. +- `spring.redis.cluster.timeout`: Timeout (in milliseconds) for cluster operations. +- `spring.redis.cluster.max-redirects`: Number of allowed cluster redirections. +- `spring.redis.cluster.password`: Password to access a password-protected Redis Cluster. Must equal across all nodes. +==== + NOTE: The initial configuration points driver libraries to an initial set of cluster nodes. Changes resulting from live cluster reconfiguration will only be kept in the native driver and not be written back to the configuration. == Working With Redis Cluster Connection diff --git a/src/main/java/org/springframework/data/redis/connection/RedisClusterConfiguration.java b/src/main/java/org/springframework/data/redis/connection/RedisClusterConfiguration.java index 43cf45d98..37038f14b 100644 --- a/src/main/java/org/springframework/data/redis/connection/RedisClusterConfiguration.java +++ b/src/main/java/org/springframework/data/redis/connection/RedisClusterConfiguration.java @@ -27,6 +27,7 @@ import java.util.Set; import org.springframework.core.env.MapPropertySource; import org.springframework.core.env.PropertySource; +import org.springframework.util.Assert; import org.springframework.util.NumberUtils; import org.springframework.util.StringUtils; @@ -36,6 +37,7 @@ import org.springframework.util.StringUtils; * environment. * * @author Christoph Strobl + * @author Mark Paluch * @since 1.7 */ public class RedisClusterConfiguration { @@ -43,10 +45,12 @@ public class RedisClusterConfiguration { private static final String REDIS_CLUSTER_NODES_CONFIG_PROPERTY = "spring.redis.cluster.nodes"; private static final String REDIS_CLUSTER_TIMEOUT_CONFIG_PROPERTY = "spring.redis.cluster.timeout"; private static final String REDIS_CLUSTER_MAX_REDIRECTS_CONFIG_PROPERTY = "spring.redis.cluster.max-redirects"; + private static final String REDIS_CLUSTER_PASSWORD_PROPERTY = "spring.redis.cluster.password"; private Set clusterNodes; private Long clusterTimeout; private Integer maxRedirects; + private String password; /** * Creates new {@link RedisClusterConfiguration}. @@ -69,7 +73,7 @@ public class RedisClusterConfiguration { * {@literal null}. */ public RedisClusterConfiguration(Collection clusterNodes) { - this(new MapPropertySource("RedisClusterConfiguration", asMap(clusterNodes, -1, -1))); + this(new MapPropertySource("RedisClusterConfiguration", asMap(clusterNodes, -1, -1, null))); } /** @@ -80,6 +84,7 @@ public class RedisClusterConfiguration { * spring.redis.cluster.nodes=127.0.0.1:23679,127.0.0.1:23680,127.0.0.1:23681 * spring.redis.cluster.timeout=5 * spring.redis.cluster.max-redirects=3 + * spring.redis.cluster.password=foobar * * * @@ -103,6 +108,9 @@ public class RedisClusterConfiguration { this.maxRedirects = NumberUtils.parseNumber( propertySource.getProperty(REDIS_CLUSTER_MAX_REDIRECTS_CONFIG_PROPERTY).toString(), Integer.class); } + if (propertySource.containsProperty(REDIS_CLUSTER_PASSWORD_PROPERTY)) { + this.password = propertySource.getProperty(REDIS_CLUSTER_PASSWORD_PROPERTY).toString(); + } } /** @@ -156,6 +164,14 @@ public class RedisClusterConfiguration { return clusterTimeout != null && clusterTimeout > Long.MIN_VALUE ? clusterTimeout : null; } + /** + * + * @param clusterTimeout + */ + public void setClusterTimeout(long clusterTimeout) { + this.clusterTimeout = clusterTimeout; + } + /** * @return */ @@ -163,6 +179,30 @@ public class RedisClusterConfiguration { return maxRedirects != null && maxRedirects > Integer.MIN_VALUE ? maxRedirects : null; } + /** + * + * @param maxRedirects + */ + public void setMaxRedirects(int maxRedirects) { + Assert.isTrue(maxRedirects >= 0, "MaxRedirects must be greater or equal to 0"); + this.maxRedirects = maxRedirects; + } + + /** + * @return + */ + public String getPassword() { + return password; + } + + /** + * + * @param password can be {@literal null} or empty. + */ + public void setPassword(String password) { + this.password = password; + } + /** * @param host * @param port @@ -189,11 +229,13 @@ public class RedisClusterConfiguration { } /** - * @param master must not be {@literal null} or empty. - * @param clusterHostAndPorts must not be {@literal null}. + * @param clusterHostAndPorts must not be {@literal null} or empty. + * @param timeout + * @param redirects + * @param password can be {@literal null} or empty. * @return */ - private static Map asMap(Collection clusterHostAndPorts, long timeout, int redirects) { + private static Map asMap(Collection clusterHostAndPorts, long timeout, int redirects, String password) { notNull(clusterHostAndPorts, "ClusterHostAndPorts must not be null!"); @@ -205,6 +247,9 @@ public class RedisClusterConfiguration { if (redirects >= 0) { map.put(REDIS_CLUSTER_MAX_REDIRECTS_CONFIG_PROPERTY, Integer.valueOf(redirects)); } + if (StringUtils.hasText(password)) { + map.put(REDIS_CLUSTER_PASSWORD_PROPERTY, password); + } return map; } diff --git a/src/main/java/org/springframework/data/redis/connection/jedis/JedisConnectionFactory.java b/src/main/java/org/springframework/data/redis/connection/jedis/JedisConnectionFactory.java index 7b44bce16..ad576b72e 100644 --- a/src/main/java/org/springframework/data/redis/connection/jedis/JedisConnectionFactory.java +++ b/src/main/java/org/springframework/data/redis/connection/jedis/JedisConnectionFactory.java @@ -62,6 +62,7 @@ import redis.clients.util.Pool; * @author Costin Leau * @author Thomas Darimont * @author Christoph Strobl + * @author Mark Paluch */ public class JedisConnectionFactory implements InitializingBean, DisposableBean, RedisConnectionFactory { @@ -292,8 +293,12 @@ public class JedisConnectionFactory implements InitializingBean, DisposableBean, hostAndPort.add(new HostAndPort(node.getHost(), node.getPort())); } - int timeout = clusterConfig.getClusterTimeout() != null ? clusterConfig.getClusterTimeout().intValue() : 1; + int timeout = clusterConfig.getClusterTimeout() != null ? clusterConfig.getClusterTimeout().intValue() : this.timeout; int redirects = clusterConfig.getMaxRedirects() != null ? clusterConfig.getMaxRedirects().intValue() : 5; + + if (StringUtils.hasText(clusterConfig.getPassword())) { + throw new UnsupportedOperationException("Jedis does not support password protected Redis Cluster configurations"); + } if (poolConfig != null) { return new JedisCluster(hostAndPort, timeout, redirects, poolConfig); diff --git a/src/main/java/org/springframework/data/redis/connection/lettuce/LettuceConnectionFactory.java b/src/main/java/org/springframework/data/redis/connection/lettuce/LettuceConnectionFactory.java index 2aa73e57b..bfd486fb3 100644 --- a/src/main/java/org/springframework/data/redis/connection/lettuce/LettuceConnectionFactory.java +++ b/src/main/java/org/springframework/data/redis/connection/lettuce/LettuceConnectionFactory.java @@ -49,6 +49,7 @@ import com.lambdaworks.redis.RedisException; import com.lambdaworks.redis.RedisFuture; import com.lambdaworks.redis.RedisURI; import com.lambdaworks.redis.cluster.RedisClusterClient; +import org.springframework.util.StringUtils; /** * Connection factory creating Lettuce-based connections. @@ -464,7 +465,16 @@ public class LettuceConnectionFactory implements InitializingBean, DisposableBea List initialUris = new ArrayList(); for (RedisNode node : this.clusterConfiguration.getClusterNodes()) { - initialUris.add(new RedisURI(node.getHost(), node.getPort(), this.timeout, TimeUnit.MILLISECONDS)); + long timeout = this.clusterConfiguration.getClusterTimeout() != null ? this.clusterConfiguration.getClusterTimeout() : this.timeout; + RedisURI redisURI = new RedisURI(node.getHost(), node.getPort(), timeout, TimeUnit.MILLISECONDS); + + if(StringUtils.hasText(this.clusterConfiguration.getPassword())){ + redisURI.setPassword(this.clusterConfiguration.getPassword()); + }else if(StringUtils.hasText(password)){ + redisURI.setPassword(password); + } + + initialUris.add(redisURI); } RedisClusterClient clusterClient = new RedisClusterClient(initialUris); diff --git a/src/test/java/org/springframework/data/redis/connection/RedisClusterConfigurationUnitTests.java b/src/test/java/org/springframework/data/redis/connection/RedisClusterConfigurationUnitTests.java index 37df50ec3..036f91345 100644 --- a/src/test/java/org/springframework/data/redis/connection/RedisClusterConfigurationUnitTests.java +++ b/src/test/java/org/springframework/data/redis/connection/RedisClusterConfigurationUnitTests.java @@ -31,6 +31,7 @@ import org.springframework.util.StringUtils; /** * @author Christoph Strobl + * @author Mark Paluch */ public class RedisClusterConfigurationUnitTests { @@ -125,12 +126,14 @@ public class RedisClusterConfigurationUnitTests { propertySource.setProperty("spring.redis.cluster.timeout", "10"); propertySource.setProperty("spring.redis.cluster.nodes", HOST_AND_PORT_1); propertySource.setProperty("spring.redis.cluster.max-redirects", "5"); + propertySource.setProperty("spring.redis.cluster.password", "foobar"); RedisClusterConfiguration config = new RedisClusterConfiguration(propertySource); assertThat(config.getMaxRedirects(), is(5)); assertThat(config.getClusterTimeout(), is(10L)); assertThat(config.getClusterNodes(), hasItems(new RedisNode("127.0.0.1", 123))); + assertThat(config.getPassword(), is("foobar")); } /**