Merge pull request #5128 from christophstrobl/issue/sd-redis-1.7.0-cluster-support
* pr/5128: Polish contribution Add Redis Cluster support
This commit is contained in:
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2012-2015 the original author or authors.
|
||||
* Copyright 2012-2016 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.
|
||||
@@ -29,10 +29,12 @@ 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.ConditionalOnMissingClass;
|
||||
import org.springframework.boot.autoconfigure.data.redis.RedisProperties.Cluster;
|
||||
import org.springframework.boot.autoconfigure.data.redis.RedisProperties.Sentinel;
|
||||
import org.springframework.boot.context.properties.EnableConfigurationProperties;
|
||||
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;
|
||||
@@ -76,6 +78,9 @@ public class RedisAutoConfiguration {
|
||||
@Autowired(required = false)
|
||||
private RedisSentinelConfiguration sentinelConfiguration;
|
||||
|
||||
@Autowired(required = false)
|
||||
private RedisClusterConfiguration clusterConfiguration;
|
||||
|
||||
protected final JedisConnectionFactory applyProperties(
|
||||
JedisConnectionFactory factory) {
|
||||
factory.setHostName(this.properties.getHost());
|
||||
@@ -104,21 +109,41 @@ public class RedisAutoConfiguration {
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a {@link RedisClusterConfiguration} if necessary.
|
||||
* @return {@literal null} if no cluster settings are set.
|
||||
*/
|
||||
protected final RedisClusterConfiguration getClusterConfiguration() {
|
||||
if (this.clusterConfiguration != null) {
|
||||
return this.clusterConfiguration;
|
||||
}
|
||||
if (this.properties.getCluster() == null) {
|
||||
return null;
|
||||
}
|
||||
Cluster clusterProperties = this.properties.getCluster();
|
||||
RedisClusterConfiguration config = new RedisClusterConfiguration(
|
||||
clusterProperties.getNodes());
|
||||
|
||||
if (clusterProperties.getMaxRedirects() != null) {
|
||||
config.setMaxRedirects(config.getMaxRedirects());
|
||||
}
|
||||
return config;
|
||||
}
|
||||
|
||||
private List<RedisNode> createSentinels(Sentinel sentinel) {
|
||||
List<RedisNode> sentinels = new ArrayList<RedisNode>();
|
||||
String nodes = sentinel.getNodes();
|
||||
for (String node : StringUtils.commaDelimitedListToStringArray(nodes)) {
|
||||
List<RedisNode> nodes = new ArrayList<RedisNode>();
|
||||
for (String node : StringUtils.commaDelimitedListToStringArray(sentinel.getNodes())) {
|
||||
try {
|
||||
String[] parts = StringUtils.split(node, ":");
|
||||
Assert.state(parts.length == 2, "Must be defined as 'host:port'");
|
||||
sentinels.add(new RedisNode(parts[0], Integer.valueOf(parts[1])));
|
||||
nodes.add(new RedisNode(parts[0], Integer.valueOf(parts[1])));
|
||||
}
|
||||
catch (RuntimeException ex) {
|
||||
throw new IllegalStateException(
|
||||
"Invalid redis sentinel " + "property '" + node + "'", ex);
|
||||
}
|
||||
}
|
||||
return sentinels;
|
||||
return nodes;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -135,9 +160,18 @@ public class RedisAutoConfiguration {
|
||||
@ConditionalOnMissingBean(RedisConnectionFactory.class)
|
||||
public JedisConnectionFactory redisConnectionFactory()
|
||||
throws UnknownHostException {
|
||||
return applyProperties(new JedisConnectionFactory(getSentinelConfig()));
|
||||
return applyProperties(createJedisConnectionFactory());
|
||||
}
|
||||
|
||||
private JedisConnectionFactory createJedisConnectionFactory() {
|
||||
if (getSentinelConfig() != null) {
|
||||
return new JedisConnectionFactory(getSentinelConfig());
|
||||
}
|
||||
if (getClusterConfiguration() != null) {
|
||||
return new JedisConnectionFactory(getClusterConfiguration());
|
||||
}
|
||||
return new JedisConnectionFactory();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -156,10 +190,16 @@ public class RedisAutoConfiguration {
|
||||
}
|
||||
|
||||
private JedisConnectionFactory createJedisConnectionFactory() {
|
||||
if (this.properties.getPool() != null) {
|
||||
return new JedisConnectionFactory(getSentinelConfig(), jedisPoolConfig());
|
||||
JedisPoolConfig poolConfig = this.properties.getPool() != null ? jedisPoolConfig()
|
||||
: new JedisPoolConfig();
|
||||
|
||||
if (getSentinelConfig() != null) {
|
||||
return new JedisConnectionFactory(getSentinelConfig(), poolConfig);
|
||||
}
|
||||
return new JedisConnectionFactory(getSentinelConfig());
|
||||
if (getClusterConfiguration() != null) {
|
||||
return new JedisConnectionFactory(getClusterConfiguration(), poolConfig);
|
||||
}
|
||||
return new JedisConnectionFactory(poolConfig);
|
||||
}
|
||||
|
||||
private JedisPoolConfig jedisPoolConfig() {
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2012-2015 the original author or authors.
|
||||
* Copyright 2012-2016 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.
|
||||
@@ -16,6 +16,8 @@
|
||||
|
||||
package org.springframework.boot.autoconfigure.data.redis;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import org.springframework.boot.context.properties.ConfigurationProperties;
|
||||
|
||||
/**
|
||||
@@ -57,6 +59,8 @@ public class RedisProperties {
|
||||
|
||||
private Sentinel sentinel;
|
||||
|
||||
private Cluster cluster;
|
||||
|
||||
public int getDatabase() {
|
||||
return this.database;
|
||||
}
|
||||
@@ -113,6 +117,14 @@ public class RedisProperties {
|
||||
this.pool = pool;
|
||||
}
|
||||
|
||||
public Cluster getCluster() {
|
||||
return this.cluster;
|
||||
}
|
||||
|
||||
public void setCluster(Cluster cluster) {
|
||||
this.cluster = cluster;
|
||||
}
|
||||
|
||||
/**
|
||||
* Pool properties.
|
||||
*/
|
||||
@@ -174,6 +186,42 @@ public class RedisProperties {
|
||||
public void setMaxWait(int maxWait) {
|
||||
this.maxWait = maxWait;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Cluster properties.
|
||||
*/
|
||||
public static class Cluster {
|
||||
|
||||
/**
|
||||
* Comma-separated list of "host:port" pairs to bootstrap from. This represents
|
||||
* an "initial" list of cluster nodes and is required to have at least one entry.
|
||||
*/
|
||||
private List<String> nodes;
|
||||
|
||||
/**
|
||||
* Maximum number of redirects to follow when executing commands across the
|
||||
* cluster.
|
||||
*/
|
||||
private Integer maxRedirects;
|
||||
|
||||
public List<String> getNodes() {
|
||||
return this.nodes;
|
||||
}
|
||||
|
||||
public void setNodes(List<String> nodes) {
|
||||
this.nodes = nodes;
|
||||
}
|
||||
|
||||
public Integer getMaxRedirects() {
|
||||
return this.maxRedirects;
|
||||
}
|
||||
|
||||
public void setMaxRedirects(Integer maxRedirects) {
|
||||
this.maxRedirects = maxRedirects;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -206,5 +254,6 @@ public class RedisProperties {
|
||||
public void setNodes(String nodes) {
|
||||
this.nodes = nodes;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2012-2015 the original author or authors.
|
||||
* Copyright 2012-2016 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.
|
||||
@@ -96,7 +96,7 @@ public class RedisAutoConfigurationTests {
|
||||
@Test
|
||||
public void testRedisConfigurationWithSentinel() throws Exception {
|
||||
List<String> sentinels = Arrays.asList("127.0.0.1:26379", "127.0.0.1:26380");
|
||||
if (isAtLeastOneSentinelAvailable(sentinels)) {
|
||||
if (isAtLeastOneNodeAvailable(sentinels)) {
|
||||
load("spring.redis.sentinel.master:mymaster", "spring.redis.sentinel.nodes:"
|
||||
+ StringUtils.collectionToCommaDelimitedString(sentinels));
|
||||
assertThat(this.context.getBean(JedisConnectionFactory.class)
|
||||
@@ -104,9 +104,21 @@ public class RedisAutoConfigurationTests {
|
||||
}
|
||||
}
|
||||
|
||||
private boolean isAtLeastOneSentinelAvailable(List<String> sentinels) {
|
||||
for (String sentinel : sentinels) {
|
||||
if (isSentinelAvailable(sentinel)) {
|
||||
@Test
|
||||
public void testRedisConfigurationWithCluster() throws Exception {
|
||||
List<String> clusterNodes = Arrays.asList("127.0.0.1:27379", "127.0.0.1:27380");
|
||||
if (isAtLeastOneNodeAvailable(clusterNodes)) {
|
||||
load("spring.redis.cluster.nodes[0]:" + clusterNodes.get(0),
|
||||
"spring.redis.cluster.nodes[1]:" + clusterNodes.get(1));
|
||||
assertThat(
|
||||
this.context.getBean(JedisConnectionFactory.class)
|
||||
.getClusterConnection()).isNotNull();
|
||||
}
|
||||
}
|
||||
|
||||
private boolean isAtLeastOneNodeAvailable(List<String> nodes) {
|
||||
for (String node : nodes) {
|
||||
if (isAvailable(node)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@@ -114,7 +126,7 @@ public class RedisAutoConfigurationTests {
|
||||
return false;
|
||||
}
|
||||
|
||||
private boolean isSentinelAvailable(String node) {
|
||||
private boolean isAvailable(String node) {
|
||||
Jedis jedis = null;
|
||||
try {
|
||||
String[] hostAndPort = node.split(":");
|
||||
|
||||
@@ -685,6 +685,8 @@ content into your application; rather pick only the properties that you need.
|
||||
spring.mongodb.embedded.version=2.6.10 # Version of Mongo to use.
|
||||
|
||||
# REDIS ({sc-spring-boot-autoconfigure}/redis/RedisProperties.{sc-ext}[RedisProperties])
|
||||
spring.redis.cluster.max-redirects= # Maximum number of redirects to follow when executing commands across the cluster.
|
||||
spring.redis.cluster.nodes= # Comma-separated list of "host:port" pairs to bootstrap from.
|
||||
spring.redis.database=0 # Database index used by the connection factory.
|
||||
spring.redis.host=localhost # Redis server host.
|
||||
spring.redis.password= # Login password of the redis server.
|
||||
|
||||
Reference in New Issue
Block a user