DATAREDIS-762 - Polishing.

Introduce marker interface RedisConfiguration along with several others providing access to specific setup scenarios like cluster and sentinel.

Original Pull Request: #306
This commit is contained in:
Christoph Strobl
2018-03-19 10:46:29 +01:00
parent bb990b14ae
commit 4a064c5ad0
12 changed files with 582 additions and 285 deletions

View File

@@ -27,6 +27,7 @@ import java.util.Set;
import org.springframework.core.env.MapPropertySource;
import org.springframework.core.env.PropertySource;
import org.springframework.data.redis.connection.RedisConfiguration.ClusterConfiguration;
import org.springframework.lang.Nullable;
import org.springframework.util.Assert;
import org.springframework.util.NumberUtils;
@@ -41,7 +42,7 @@ import org.springframework.util.StringUtils;
* @author Mark Paluch
* @since 1.7
*/
public class RedisClusterConfiguration {
public class RedisClusterConfiguration implements RedisConfiguration, ClusterConfiguration {
private static final String REDIS_CLUSTER_NODES_CONFIG_PROPERTY = "spring.redis.cluster.nodes";
private static final String REDIS_CLUSTER_MAX_REDIRECTS_CONFIG_PROPERTY = "spring.redis.cluster.max-redirects";
@@ -120,11 +121,11 @@ public class RedisClusterConfiguration {
}
}
/**
* Returns an {@link Collections#unmodifiableSet(Set)} of {@literal cluster nodes}.
*
* @return {@link Set} of nodes. Never {@literal null}.
/*
* (non-Javadoc)
* @see org.springframework.data.redis.connection.RedisConfiguration.ClusterConfiguration#getClusterNodes()
*/
@Override
public Set<RedisNode> getClusterNodes() {
return Collections.unmodifiableSet(clusterNodes);
}
@@ -149,9 +150,11 @@ public class RedisClusterConfiguration {
return this;
}
/**
* @return max number of redirects to follow or {@literal null} if not set.
/*
* (non-Javadoc)
* @see org.springframework.data.redis.connection.RedisConfiguration.ClusterConfiguration#getMaxRedirects()
*/
@Override
public Integer getMaxRedirects() {
return maxRedirects != null && maxRedirects > Integer.MIN_VALUE ? maxRedirects : null;
}
@@ -181,20 +184,20 @@ public class RedisClusterConfiguration {
}
}
/**
* Get the {@link RedisPassword} defined.
*
* @return never {@literal null}.
* @since 2.0
/*
* (non-Javadoc)
* @see org.springframework.data.redis.connection.RedisConfiguration.WithPassword#getPassword()
*/
@Override
public RedisPassword getPassword() {
return password;
}
/**
* @param password must not be {@literal null}.
* @since 2.0
/*
* (non-Javadoc)
* @see org.springframework.data.redis.connection.RedisConfiguration.WithPassword#setPassword(org.springframework.data.redis.connection.RedisPassword)
*/
@Override
public void setPassword(RedisPassword password) {
Assert.notNull(password, "RedisPassword must not be null!");

View File

@@ -0,0 +1,348 @@
/*
* Copyright 2018 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
*
* http://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.data.redis.connection;
import java.util.Collections;
import java.util.List;
import java.util.Set;
import java.util.function.Supplier;
import org.springframework.lang.Nullable;
import org.springframework.util.Assert;
/**
* Marker interface for configuration classes related to Redis connection setup. As the setup scenarios are quite
* diverse instead of struggling with unifying those, {@link RedisConfiguration} provides means to identify
* configurations for the individual purposes.
*
* @author Christoph Strobl
* @since 2.1
*/
public interface RedisConfiguration {
/**
* Get the configured database index if the current {@link RedisConfiguration} is
* {@link #isDatabaseIndexAware(RedisConfiguration) database aware} or evaluate and return the value of the given
* {@link Supplier}.
*
* @param other a {@code Supplier} whose result is returned if given {@link RedisConfiguration} is not
* {@link #isDatabaseIndexAware(RedisConfiguration) database aware}.
* @return never {@literal null}.
* @throws IllegalArgumentException if {@code other} is {@literal null}.
*/
default Integer getDatabaseOrElse(Supplier<Integer> other) {
return getDatabaseOrElse(this, other);
}
/**
* Get the configured {@link RedisPassword} if the current {@link RedisConfiguration} is
* {@link #isPasswordAware(RedisConfiguration) password aware} or evaluate and return the value of the given
* {@link Supplier}.
*
* @param other a {@code Supplier} whose result is returned if given {@link RedisConfiguration} is not
* {@link #isPasswordAware(RedisConfiguration) password aware}.
* @return never {@literal null}.
* @throws IllegalArgumentException if {@code other} is {@literal null}.
*/
default RedisPassword getPasswordOrElse(Supplier<RedisPassword> other) {
return getPasswordOrElse(this, other);
}
/**
* @param configuration can be {@literal null}.
* @return {@code true} if given {@link RedisConfiguration} is instance of {@link WithPassword}.
*/
static boolean isPasswordAware(@Nullable RedisConfiguration configuration) {
return configuration instanceof WithPassword;
}
/**
* @param configuration can be {@literal null}.
* @return {@code true} if given {@link RedisConfiguration} is instance of {@link WithDatabaseIndex}.
*/
static boolean isDatabaseIndexAware(@Nullable RedisConfiguration configuration) {
return configuration instanceof WithDatabaseIndex;
}
/**
* @param configuration can be {@literal null}.
* @return {@code true} if given {@link RedisConfiguration} is instance of {@link SentinelConfiguration}.
*/
static boolean isSentinelConfiguration(@Nullable RedisConfiguration configuration) {
return configuration instanceof SentinelConfiguration;
}
/**
* @param configuration can be {@literal null}.
* @return {@code true} if given {@link RedisConfiguration} is instance of {@link ClusterConfiguration}.
*/
static boolean isClusterConfiguration(@Nullable RedisConfiguration configuration) {
return configuration instanceof ClusterConfiguration;
}
/**
* @param configuration can be {@literal null}.
* @return {@code true} if given {@link RedisConfiguration} is instance of {@link StaticMasterSlaveConfiguration}.
*/
static boolean isStaticMasterSlaveConfiguration(@Nullable RedisConfiguration configuration) {
return configuration instanceof StaticMasterSlaveConfiguration;
}
/**
* @param configuration can be {@literal null}.
* @return {@code true} if given {@link RedisConfiguration} is instance of {@link DomainSocketConfiguration}.
*/
static boolean isDomainSocketConfiguration(@Nullable RedisConfiguration configuration) {
return configuration instanceof DomainSocketConfiguration;
}
/**
* @param configuration can be {@literal null}.
* @param other a {@code Supplier} whose result is returned if given {@link RedisConfiguration} is not
* {@link #isDatabaseIndexAware(RedisConfiguration) database aware}.
* @return never {@literal null}.
* @throws IllegalArgumentException if {@code other} is {@literal null}.
*/
static Integer getDatabaseOrElse(@Nullable RedisConfiguration configuration, Supplier<Integer> other) {
Assert.notNull(other, "Other must not be null!");
return isDatabaseIndexAware(configuration) ? ((WithDatabaseIndex) configuration).getDatabase() : other.get();
}
/**
* @param configuration can be {@literal null}.
* @param other a {@code Supplier} whose result is returned if given {@link RedisConfiguration} is not
* {@link #isPasswordAware(RedisConfiguration) password aware}.
* @return never {@literal null}.
* @throws IllegalArgumentException if {@code other} is {@literal null}.
*/
static RedisPassword getPasswordOrElse(@Nullable RedisConfiguration configuration, Supplier<RedisPassword> other) {
Assert.notNull(other, "Other must not be null!");
return isPasswordAware(configuration) ? ((WithPassword) configuration).getPassword() : other.get();
}
/**
* {@link RedisConfiguration} part suitable for configurations that may use authentication when connecting.
*
* @author Christoph Strobl
* @since 2.1
*/
interface WithPassword {
/**
* Create and set a {@link RedisPassword} for given {@link String}.
*
* @param password can be {@literal null}.
*/
default void setPassword(@Nullable String password) {
setPassword(RedisPassword.of(password));
}
/**
* Create and set a {@link RedisPassword} for given {@link String}.
*
* @param password can be {@literal null}.
*/
default void setPassword(@Nullable char[] password) {
setPassword(RedisPassword.of(password));
}
/**
* Create and set a {@link RedisPassword} for given {@link String}.
*
* @param password must not be {@literal null} use {@link RedisPassword#none()} instead.
*/
void setPassword(RedisPassword password);
/**
* Get the RedisPassword to use when connecting.
*
* @return {@link RedisPassword#none()} if none set.
*/
RedisPassword getPassword();
}
/**
* {@link RedisConfiguration} part suitable for configurations that use a specific database.
*
* @author Christoph Strobl
* @since 2.1
*/
interface WithDatabaseIndex {
/**
* Set the database index to use.
*
* @param dbIndex
*/
void setDatabase(int dbIndex);
/**
* Get the database index to use.
*
* @return {@code zero} by default.
*/
int getDatabase();
}
/**
* {@link RedisConfiguration} part suitable for configurations that use host/port combinations for connecting.
*
* @author Christoph Strobl
* @since 2.1
*/
interface WithHostAndPort {
/**
* Set the Redis server hostname
*
* @param hostName must not be {@literal null}.
*/
void setHostName(String hostName);
/**
* @return never {@literal null}.
*/
String getHostName();
/**
* Set the Redis server port.
*
* @param port
*/
void setPort(int port);
/**
* Get the Redis server port.
*
* @return
*/
int getPort();
}
/**
* {@link RedisConfiguration} part suitable for configurations that use native domain sockets for connecting.
*
* @author Christoph Strobl
* @since 2.1
*/
interface WithDomainSocket {
/**
* Set the socket.
*
* @param socket path to the Redis socket. Must not be {@literal null}.
*/
void setSocket(String socket);
/**
* Get the domain socket.
*
* @return path to the Redis socket.
*/
String getSocket();
}
/**
* Configuration interface suitable for Redis Sentinel environments.
*
* @author Christoph Strobl
* @since 2.1
*/
interface SentinelConfiguration extends WithDatabaseIndex, WithPassword {
/**
* Set the name of the master node.
*
* @param name must not be {@literal null}.
*/
default void setMaster(final String name) {
Assert.notNull(name, "Name of sentinel master must not be null.");
setMaster(() -> name);
}
/**
* Set the master node.
*
* @param master must not be {@literal null}.
*/
void setMaster(NamedNode master);
/**
* Get the {@literal Sentinel} master node.
*
* @return get the master node or {@literal null} if not set.
*/
@Nullable
NamedNode getMaster();
/**
* Returns an {@link Collections#unmodifiableSet(Set)} of {@literal Sentinels}.
*
* @return {@link Set} of sentinels. Never {@literal null}.
*/
Set<RedisNode> getSentinels();
}
/**
* Configuration interface suitable for Redis cluster environments.
*
* @author Christoph Strobl
* @since 2.1
*/
interface ClusterConfiguration extends WithPassword {
/**
* Returns an {@link Collections#unmodifiableSet(Set)} of {@literal cluster nodes}.
*
* @return {@link Set} of nodes. Never {@literal null}.
*/
Set<RedisNode> getClusterNodes();
/**
* @return max number of redirects to follow or {@literal null} if not set.
*/
@Nullable
Integer getMaxRedirects();
}
/**
* Configuration interface suitable for Redis master/slave environments with fixed hosts.
*
* @author Christoph Strobl
* @since 2.1
*/
interface StaticMasterSlaveConfiguration extends WithDatabaseIndex, WithPassword {
/**
* @return unmodifiable {@link List} of {@link RedisStandaloneConfiguration nodes}.
*/
List<RedisStandaloneConfiguration> getNodes();
}
/**
* Configuration interface suitable for single node redis connections using local unix domain socket.
*
* @author Christoph Strobl
* @since 2.1
*/
interface DomainSocketConfiguration extends WithDomainSocket, WithDatabaseIndex, WithPassword {
}
}

View File

@@ -27,6 +27,7 @@ import java.util.Set;
import org.springframework.core.env.MapPropertySource;
import org.springframework.core.env.PropertySource;
import org.springframework.data.redis.connection.RedisConfiguration.SentinelConfiguration;
import org.springframework.lang.Nullable;
import org.springframework.util.Assert;
import org.springframework.util.StringUtils;
@@ -41,7 +42,7 @@ import org.springframework.util.StringUtils;
* @author Mark Paluch
* @since 1.4
*/
public class RedisSentinelConfiguration {
public class RedisSentinelConfiguration implements RedisConfiguration, SentinelConfiguration {
private static final String REDIS_SENTINEL_MASTER_CONFIG_PROPERTY = "spring.redis.sentinel.master";
private static final String REDIS_SENTINEL_NODES_CONFIG_PROPERTY = "spring.redis.sentinel.nodes";
@@ -118,10 +119,9 @@ public class RedisSentinelConfiguration {
}
}
/**
* Returns an {@link Collections#unmodifiableSet(Set)} of {@literal Sentinels}.
*
* @return {@link Set} of sentinels. Never {@literal null}.
/*
* (non-Javadoc)
* @see org.springframework.data.redis.connection.RedisConfiguration.SentinelConfiguration#getSentinels()
*/
public Set<RedisNode> getSentinels() {
return Collections.unmodifiableSet(sentinels);
@@ -138,21 +138,9 @@ public class RedisSentinelConfiguration {
this.sentinels.add(sentinel);
}
/**
* Set the master node via its name.
*
* @param name must not be {@literal null}.
*/
public void setMaster(final String name) {
notNull(name, "Name of sentinel master must not be null.");
setMaster(() -> name);
}
/**
* Set the master.
*
* @param master must not be {@literal null}.
/*
* (non-Javadoc)
* @see org.springframework.data.redis.connection.RedisConfiguration.SentinelConfiguration#setMaster(org.springframework.data.redis.connection.NamedNode)
*/
public void setMaster(NamedNode master) {
@@ -160,12 +148,10 @@ public class RedisSentinelConfiguration {
this.master = master;
}
/**
* Get the {@literal Sentinel} master node.
*
* @return get the master node or {@literal null} if not set.
/*
* (non-Javadoc)
* @see org.springframework.data.redis.connection.RedisConfiguration.SentinelConfiguration#getMaster()
*/
@Nullable
public NamedNode getMaster() {
return master;
}
@@ -217,20 +203,20 @@ public class RedisSentinelConfiguration {
}
}
/**
* @return the initial db index.
* @since 2.0
/*
* (non-Javadoc)
* @see org.springframework.data.redis.connection.RedisConfiguration.WithDatabaseIndex#getDatabase()
*/
@Override
public int getDatabase() {
return database;
}
/**
* Sets the index of the database used by this connection factory. Default is 0.
*
* @param index database index.
* @since 2.0
/*
* (non-Javadoc)
* @see org.springframework.data.redis.connection.RedisConfiguration.WithDatabaseIndex#setDatabase(int)
*/
@Override
public void setDatabase(int index) {
Assert.isTrue(index >= 0, () -> String.format("Invalid DB index '%s' (a positive index required)", index));
@@ -238,18 +224,20 @@ public class RedisSentinelConfiguration {
this.database = index;
}
/**
* @return never {@literal null}.
* @since 2.0
/*
* (non-Javadoc)
* @see org.springframework.data.redis.connection.RedisConfiguration.WithPassword#getPassword()
*/
@Override
public RedisPassword getPassword() {
return password;
}
/**
* @param password must not be {@literal null}.
* @since 2.0
/*
* (non-Javadoc)
* @see org.springframework.data.redis.connection.RedisConfiguration.WithPassword#setPassword(org.springframework.data.redis.connection.RedisPassword)
*/
@Override
public void setPassword(RedisPassword password) {
Assert.notNull(password, "RedisPassword must not be null!");

View File

@@ -15,6 +15,7 @@
*/
package org.springframework.data.redis.connection;
import org.springframework.data.redis.connection.RedisConfiguration.DomainSocketConfiguration;
import org.springframework.util.Assert;
/**
@@ -25,7 +26,7 @@ import org.springframework.util.Assert;
* @author Christoph Strobl
* @since 2.1
*/
public class RedisSocketConfiguration {
public class RedisSocketConfiguration implements RedisConfiguration, DomainSocketConfiguration {
private static final String DEFAULT_SOCKET = "/tmp/redis.sock";
@@ -50,34 +51,40 @@ public class RedisSocketConfiguration {
this.socket = socket;
}
/**
* @return path to the Redis socket.
/*
* (non-Javadoc)
* @see org.springframework.data.redis.connection.RedisConfiguration.WithDomainSocket#getSocket()
*/
@Override
public String getSocket() {
return socket;
}
/**
* @param socket path to the Redis socket.
/*
* (non-Javadoc)
* @see org.springframework.data.redis.connection.RedisConfiguration.WithDomainSocket#setSocket(java.lang.String)
*/
@Override
public void setSocket(String socket) {
Assert.hasText(socket, "Socket must not be null nor empty!");
this.socket = socket;
}
/**
* @return the db index.
/*
* (non-Javadoc)
* @see org.springframework.data.redis.connection.RedisConfiguration.WithDatabaseIndex#getDatabase()
*/
@Override
public int getDatabase() {
return database;
}
/**
* Sets the index of the database used by this connection factory. Default is 0.
*
* @param index database index.
/*
* (non-Javadoc)
* @see org.springframework.data.redis.connection.RedisConfiguration.WithDatabaseIndex#setDatabase(int)
*/
@Override
public void setDatabase(int index) {
Assert.isTrue(index >= 0, () -> String.format("Invalid DB index '%s' (a positive index required)", index));
@@ -85,16 +92,20 @@ public class RedisSocketConfiguration {
this.database = index;
}
/**
* @return never {@literal null}.
/*
* (non-Javadoc)
* @see org.springframework.data.redis.connection.RedisConfiguration.WithPassword#getPassword()
*/
@Override
public RedisPassword getPassword() {
return password;
}
/**
* @param password must not be {@literal null}.
/*
* (non-Javadoc)
* @see org.springframework.data.redis.connection.RedisConfiguration.WithPassword#setPassword(org.springframework.data.redis.connection.RedisPassword)
*/
@Override
public void setPassword(RedisPassword password) {
Assert.notNull(password, "RedisPassword must not be null!");

View File

@@ -15,6 +15,9 @@
*/
package org.springframework.data.redis.connection;
import org.springframework.data.redis.connection.RedisConfiguration.WithDatabaseIndex;
import org.springframework.data.redis.connection.RedisConfiguration.WithHostAndPort;
import org.springframework.data.redis.connection.RedisConfiguration.WithPassword;
import org.springframework.util.Assert;
/**
@@ -25,7 +28,8 @@ import org.springframework.util.Assert;
* @author Christoph Strobl
* @since 2.0
*/
public class RedisStandaloneConfiguration {
public class RedisStandaloneConfiguration
implements RedisConfiguration, WithHostAndPort, WithPassword, WithDatabaseIndex {
private static final String DEFAULT_HOST = "localhost";
private static final int DEFAULT_PORT = 6379;
@@ -65,46 +69,55 @@ public class RedisStandaloneConfiguration {
this.port = port;
}
/**
* @return the hostname or ip of the Redis node.
/*
* (non-Javadoc)
* @see org.springframework.data.redis.connection.RedisConfiguration.WithHostAndPort#getHostName()
*/
@Override
public String getHostName() {
return hostName;
}
/**
* @return the port or the Redis node.
/*
* (non-Javadoc)
* @see org.springframework.data.redis.connection.RedisConfiguration.WithHostAndPort#getPort()
*/
@Override
public int getPort() {
return port;
}
/**
* @param hostName the hostname or ip of the Redis node.
/*
* (non-Javadoc)
* @see org.springframework.data.redis.connection.RedisConfiguration.WithHostAndPort#setHostName(java.lang.String)
*/
@Override
public void setHostName(String hostName) {
this.hostName = hostName;
}
/**
* @param port the Redis node port to connect to.
/*
* (non-Javadoc)
* @see org.springframework.data.redis.connection.RedisConfiguration.WithHostAndPort#setPort(int)
*/
public void setPort(int port) {
this.port = port;
}
/**
* @return the db index.
/*
* (non-Javadoc)
* @see org.springframework.data.redis.connection.RedisConfiguration.WithDatabaseIndex#getDatabase()
*/
@Override
public int getDatabase() {
return database;
}
/**
* Sets the index of the database used by this connection factory. Default is 0.
*
* @param index database index.
/*
* (non-Javadoc)
* @see org.springframework.data.redis.connection.RedisConfiguration.WithDatabaseIndex#setDatabase(int)
*/
@Override
public void setDatabase(int index) {
Assert.isTrue(index >= 0, () -> String.format("Invalid DB index '%s' (a positive index required)", index));
@@ -112,16 +125,20 @@ public class RedisStandaloneConfiguration {
this.database = index;
}
/**
* @return never {@literal null}.
/*
* (non-Javadoc)
* @see org.springframework.data.redis.connection.RedisConfiguration.WithPassword#getPassword()
*/
@Override
public RedisPassword getPassword() {
return password;
}
/**
* @param password must not be {@literal null}.
/*
* (non-Javadoc)
* @see org.springframework.data.redis.connection.RedisConfiguration.WithPassword#setPassword(org.springframework.data.redis.connection.RedisPassword)
*/
@Override
public void setPassword(RedisPassword password) {
Assert.notNull(password, "RedisPassword must not be null!");

View File

@@ -19,16 +19,19 @@ import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import org.springframework.data.redis.connection.RedisConfiguration.StaticMasterSlaveConfiguration;
import org.springframework.util.Assert;
/**
* Configuration class used for setting up {@link RedisConnection} via {@link RedisConnectionFactory} using connecting
* to <a href="https://aws.amazon.com/documentation/elasticache/">AWS ElastiCache with Read Replicas</a> .
* Configuration class used for setting up {@link RedisConnection} via {@link RedisConnectionFactory} using the provided
* Master / Slave configuration to nodes know to not change address. Eg. when connecting to
* <a href="https://aws.amazon.com/documentation/elasticache/">AWS ElastiCache with Read Replicas</a> .
*
* @author Mark Paluch
* @author Christoph Strobl
* @since 2.1
*/
public class RedisElastiCacheConfiguration {
public class RedisStaticMasterSlaveConfiguration implements RedisConfiguration, StaticMasterSlaveConfiguration {
private static final int DEFAULT_PORT = 6379;
@@ -37,21 +40,21 @@ public class RedisElastiCacheConfiguration {
private RedisPassword password = RedisPassword.none();
/**
* Create a new {@link RedisElastiCacheConfiguration} given {@code hostName}.
* Create a new {@link StaticMasterSlaveConfiguration} given {@code hostName}.
*
* @param hostName must not be {@literal null} or empty.
*/
public RedisElastiCacheConfiguration(String hostName) {
public RedisStaticMasterSlaveConfiguration(String hostName) {
this(hostName, DEFAULT_PORT);
}
/**
* Create a new {@link RedisElastiCacheConfiguration} given {@code hostName} and {@code port}.
* Create a new {@link StaticMasterSlaveConfiguration} given {@code hostName} and {@code port}.
*
* @param hostName must not be {@literal null} or empty.
* @param port a valid TCP port (1-65535).
*/
public RedisElastiCacheConfiguration(String hostName, int port) {
public RedisStaticMasterSlaveConfiguration(String hostName, int port) {
addNode(hostName, port);
}
@@ -83,9 +86,9 @@ public class RedisElastiCacheConfiguration {
* Add a {@link RedisStandaloneConfiguration node} to the list of nodes given {@code hostName}.
*
* @param hostName must not be {@literal null} or empty.
* @return {@code this} {@link RedisElastiCacheConfiguration}.
* @return {@code this} {@link StaticMasterSlaveConfiguration}.
*/
public RedisElastiCacheConfiguration node(String hostName) {
public StaticMasterSlaveConfiguration node(String hostName) {
return node(hostName, DEFAULT_PORT);
}
@@ -94,26 +97,28 @@ public class RedisElastiCacheConfiguration {
*
* @param hostName must not be {@literal null} or empty.
* @param port a valid TCP port (1-65535).
* @return {@code this} {@link RedisElastiCacheConfiguration}.
* @return {@code this} {@link StaticMasterSlaveConfiguration}.
*/
public RedisElastiCacheConfiguration node(String hostName, int port) {
public RedisStaticMasterSlaveConfiguration node(String hostName, int port) {
addNode(hostName, port);
return this;
}
/**
* @return the db index.
/*
* (non-Javadoc)
* @see org.springframework.data.redis.connection.RedisConfiguration.WithDatabaseIndex#getDatabase()
*/
@Override
public int getDatabase() {
return database;
}
/**
* Sets the index of the database used by this connection factory. Default is 0.
*
* @param index database index.
/*
* (non-Javadoc)
* @see org.springframework.data.redis.connection.RedisConfiguration.WithDatabaseIndex#setDatabase(int)
*/
@Override
public void setDatabase(int index) {
Assert.isTrue(index >= 0, () -> String.format("Invalid DB index '%s' (a positive index required)", index));
@@ -122,16 +127,20 @@ public class RedisElastiCacheConfiguration {
this.nodes.forEach(it -> it.setDatabase(database));
}
/**
* @return never {@literal null}.
/*
* (non-Javadoc)
* @see org.springframework.data.redis.connection.RedisConfiguration.WithPassword#getPassword()
*/
@Override
public RedisPassword getPassword() {
return password;
}
/**
* @param password must not be {@literal null}.
/*
* (non-Javadoc)
* @see org.springframework.data.redis.connection.RedisConfiguration.WithPassword#setPassword(org.springframework.data.redis.connection.RedisPassword)
*/
@Override
public void setPassword(RedisPassword password) {
Assert.notNull(password, "RedisPassword must not be null!");
@@ -140,10 +149,12 @@ public class RedisElastiCacheConfiguration {
this.nodes.forEach(it -> it.setPassword(password));
}
/**
* @return list of {@link RedisStandaloneConfiguration nodes}.
/*
* (non-Javadoc)
* @see org.springframework.data.redis.connection.RedisConfiguration.StaticMasterSlaveConfiguration#getNodes()
*/
@Override
public List<RedisStandaloneConfiguration> getNodes() {
return Collections.unmodifiableList(new ArrayList<>(nodes));
return Collections.unmodifiableList(nodes);
}
}

View File

@@ -49,16 +49,10 @@ import org.springframework.dao.InvalidDataAccessResourceUsageException;
import org.springframework.data.redis.ExceptionTranslationStrategy;
import org.springframework.data.redis.PassThroughExceptionTranslationStrategy;
import org.springframework.data.redis.RedisConnectionFailureException;
import org.springframework.data.redis.connection.ClusterCommandExecutor;
import org.springframework.data.redis.connection.RedisClusterConfiguration;
import org.springframework.data.redis.connection.RedisClusterConnection;
import org.springframework.data.redis.connection.RedisConnection;
import org.springframework.data.redis.connection.RedisConnectionFactory;
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.RedisSentinelConnection;
import org.springframework.data.redis.connection.RedisStandaloneConfiguration;
import org.springframework.data.redis.connection.*;
import org.springframework.data.redis.connection.RedisConfiguration.SentinelConfiguration;
import org.springframework.data.redis.connection.RedisConfiguration.WithDatabaseIndex;
import org.springframework.data.redis.connection.RedisConfiguration.WithPassword;
import org.springframework.data.redis.connection.jedis.JedisClusterConnection.JedisClusterTopologyProvider;
import org.springframework.lang.Nullable;
import org.springframework.util.Assert;
@@ -98,8 +92,9 @@ public class JedisConnectionFactory implements InitializingBean, DisposableBean,
private boolean convertPipelineAndTxResults = true;
private RedisStandaloneConfiguration standaloneConfig = new RedisStandaloneConfiguration("localhost",
Protocol.DEFAULT_PORT);
private @Nullable RedisSentinelConfiguration sentinelConfig;
private @Nullable RedisClusterConfiguration clusterConfig;
private @Nullable RedisConfiguration configuration;
private @Nullable JedisCluster cluster;
private @Nullable ClusterCommandExecutor clusterCommandExecutor;
@@ -171,7 +166,7 @@ public class JedisConnectionFactory implements InitializingBean, DisposableBean,
*/
public JedisConnectionFactory(RedisSentinelConfiguration sentinelConfig, JedisPoolConfig poolConfig) {
this.sentinelConfig = sentinelConfig;
this.configuration = sentinelConfig;
this.clientConfiguration = MutableJedisClientConfiguration
.create(poolConfig != null ? poolConfig : new JedisPoolConfig());
}
@@ -198,7 +193,7 @@ public class JedisConnectionFactory implements InitializingBean, DisposableBean,
Assert.notNull(clusterConfig, "RedisClusterConfiguration must not be null!");
this.clusterConfig = clusterConfig;
this.configuration = clusterConfig;
this.clientConfiguration = MutableJedisClientConfiguration.create(poolConfig);
}
@@ -243,7 +238,7 @@ public class JedisConnectionFactory implements InitializingBean, DisposableBean,
Assert.notNull(sentinelConfig, "RedisSentinelConfiguration must not be null!");
this.sentinelConfig = sentinelConfig;
this.configuration = sentinelConfig;
}
/**
@@ -260,7 +255,7 @@ public class JedisConnectionFactory implements InitializingBean, DisposableBean,
Assert.notNull(clusterConfig, "RedisClusterConfiguration must not be null!");
this.clusterConfig = clusterConfig;
this.configuration = clusterConfig;
}
/**
@@ -354,7 +349,7 @@ public class JedisConnectionFactory implements InitializingBean, DisposableBean,
private Pool<Jedis> createPool() {
if (isRedisSentinelAware()) {
return createRedisSentinelPool(this.sentinelConfig);
return createRedisSentinelPool((RedisSentinelConfiguration) this.configuration);
}
return createRedisPool();
}
@@ -390,7 +385,7 @@ public class JedisConnectionFactory implements InitializingBean, DisposableBean,
private JedisCluster createCluster() {
JedisCluster cluster = createCluster(this.clusterConfig, getPoolConfig());
JedisCluster cluster = createCluster((RedisClusterConfiguration) this.configuration, getPoolConfig());
JedisClusterTopologyProvider topologyProvider = new JedisClusterTopologyProvider(cluster);
this.clusterCommandExecutor = new ClusterCommandExecutor(topologyProvider,
new JedisClusterConnection.JedisClusterNodeResourceProvider(cluster, topologyProvider), EXCEPTION_TRANSLATION);
@@ -548,16 +543,7 @@ public class JedisConnectionFactory implements InitializingBean, DisposableBean,
}
private RedisPassword getRedisPassword() {
if (isRedisSentinelAware()) {
return sentinelConfig.getPassword();
}
if (isRedisClusterAware()) {
return clusterConfig.getPassword();
}
return standaloneConfig.getPassword();
return RedisConfiguration.getPasswordOrElse(this.configuration, standaloneConfig::getPassword);
}
/**
@@ -570,13 +556,9 @@ public class JedisConnectionFactory implements InitializingBean, DisposableBean,
@Deprecated
public void setPassword(String password) {
if (isRedisSentinelAware()) {
sentinelConfig.setPassword(RedisPassword.of(password));
return;
}
if (RedisConfiguration.isPasswordAware(configuration)) {
if (isRedisClusterAware()) {
clusterConfig.setPassword(RedisPassword.of(password));
((WithPassword) configuration).setPassword(password);
return;
}
@@ -716,12 +698,7 @@ public class JedisConnectionFactory implements InitializingBean, DisposableBean,
* @return the database index.
*/
public int getDatabase() {
if (isRedisSentinelAware()) {
return sentinelConfig.getDatabase();
}
return standaloneConfig.getDatabase();
return RedisConfiguration.getDatabaseOrElse(configuration, standaloneConfig::getDatabase);
}
/**
@@ -736,8 +713,9 @@ public class JedisConnectionFactory implements InitializingBean, DisposableBean,
Assert.isTrue(index >= 0, "invalid DB index (a positive index required)");
if (isRedisSentinelAware()) {
sentinelConfig.setDatabase(index);
if (RedisConfiguration.isDatabaseIndexAware(configuration)) {
((WithDatabaseIndex) configuration).setDatabase(index);
return;
}
@@ -791,7 +769,8 @@ public class JedisConnectionFactory implements InitializingBean, DisposableBean,
*/
@Nullable
public RedisSentinelConfiguration getSentinelConfiguration() {
return sentinelConfig;
return RedisConfiguration.isSentinelConfiguration(configuration) ? (RedisSentinelConfiguration) configuration
: null;
}
/**
@@ -800,7 +779,7 @@ public class JedisConnectionFactory implements InitializingBean, DisposableBean,
*/
@Nullable
public RedisClusterConfiguration getClusterConfiguration() {
return clusterConfig;
return RedisConfiguration.isClusterConfiguration(configuration) ? (RedisClusterConfiguration) configuration : null;
}
/**
@@ -830,7 +809,7 @@ public class JedisConnectionFactory implements InitializingBean, DisposableBean,
* @since 1.4
*/
public boolean isRedisSentinelAware() {
return sentinelConfig != null;
return RedisConfiguration.isSentinelConfiguration(configuration);
}
/**
@@ -838,7 +817,7 @@ public class JedisConnectionFactory implements InitializingBean, DisposableBean,
* @since 2.0
*/
public boolean isRedisClusterAware() {
return clusterConfig != null;
return RedisConfiguration.isClusterConfiguration(configuration);
}
/* (non-Javadoc)
@@ -856,9 +835,9 @@ public class JedisConnectionFactory implements InitializingBean, DisposableBean,
private Jedis getActiveSentinel() {
Assert.notNull(this.sentinelConfig, "SentinelConfig must not be null!");
Assert.isTrue(RedisConfiguration.isSentinelConfiguration(configuration), "SentinelConfig must not be null!");
for (RedisNode node : this.sentinelConfig.getSentinels()) {
for (RedisNode node : ((SentinelConfiguration) configuration).getSentinels()) {
Jedis jedis = new Jedis(node.getHost(), node.getPort(), getConnectTimeout(), getReadTimeout());

View File

@@ -48,6 +48,10 @@ import org.springframework.data.redis.ExceptionTranslationStrategy;
import org.springframework.data.redis.PassThroughExceptionTranslationStrategy;
import org.springframework.data.redis.RedisConnectionFailureException;
import org.springframework.data.redis.connection.*;
import org.springframework.data.redis.connection.RedisConfiguration.ClusterConfiguration;
import org.springframework.data.redis.connection.RedisConfiguration.DomainSocketConfiguration;
import org.springframework.data.redis.connection.RedisConfiguration.WithDatabaseIndex;
import org.springframework.data.redis.connection.RedisConfiguration.WithPassword;
import org.springframework.data.util.Optionals;
import org.springframework.lang.Nullable;
import org.springframework.util.Assert;
@@ -69,7 +73,7 @@ import org.springframework.util.ClassUtils;
* {@link LettuceConnectionFactory client configuration}. Lettuce supports the following environmental configurations:
* <ul>
* <li>{@link RedisStandaloneConfiguration}</li>
* <li>{@link RedisElastiCacheConfiguration}</li>
* <li>{@link RedisStaticMasterSlaveConfiguration}</li>
* <li>{@link RedisSocketConfiguration}</li>
* <li>{@link RedisSentinelConfiguration}</li>
* <li>{@link RedisClusterConfiguration}</li>
@@ -102,11 +106,11 @@ public class LettuceConnectionFactory
/** Synchronization monitor for the shared Connection */
private final Object connectionMonitor = new Object();
private boolean convertPipelineAndTxResults = true;
private RedisStandaloneConfiguration standaloneConfig = new RedisStandaloneConfiguration("localhost", 6379);
private @Nullable RedisElastiCacheConfiguration elastiCacheConfiguration;
private @Nullable RedisSocketConfiguration socketConfiguration;
private @Nullable RedisSentinelConfiguration sentinelConfiguration;
private @Nullable RedisClusterConfiguration clusterConfiguration;
private @Nullable RedisConfiguration configuration;
private @Nullable ClusterCommandExecutor clusterCommandExecutor;
/**
@@ -119,8 +123,8 @@ public class LettuceConnectionFactory
/**
* Constructs a new {@link LettuceConnectionFactory} instance with default settings.
*/
public LettuceConnectionFactory(RedisStandaloneConfiguration config) {
this(config, new MutableLettuceClientConfiguration());
public LettuceConnectionFactory(RedisStandaloneConfiguration configuration) {
this(configuration, new MutableLettuceClientConfiguration());
}
/**
@@ -134,6 +138,7 @@ public class LettuceConnectionFactory
Assert.notNull(clientConfig, "LettuceClientConfiguration must not be null!");
this.clientConfiguration = clientConfig;
this.configuration = this.standaloneConfig;
}
/**
@@ -146,11 +151,11 @@ public class LettuceConnectionFactory
/**
* Constructs a new {@link LettuceConnectionFactory} instance using the given {@link RedisSocketConfiguration}.
*
* @param socketConfiguration must not be {@literal null}.
* @param redisConfiguration must not be {@literal null}.
* @since 2.1
*/
public LettuceConnectionFactory(RedisSocketConfiguration socketConfiguration) {
this(socketConfiguration, new MutableLettuceClientConfiguration());
public LettuceConnectionFactory(RedisConfiguration redisConfiguration) {
this(redisConfiguration, new MutableLettuceClientConfiguration());
}
/**
@@ -180,6 +185,7 @@ public class LettuceConnectionFactory
*/
@Deprecated
public LettuceConnectionFactory(LettucePool pool) {
this(new MutableLettuceClientConfiguration());
this.pool = pool;
}
@@ -200,42 +206,24 @@ public class LettuceConnectionFactory
Assert.notNull(standaloneConfig, "RedisStandaloneConfiguration must not be null!");
this.standaloneConfig = standaloneConfig;
this.configuration = this.standaloneConfig;
}
/**
* Constructs a new {@link LettuceConnectionFactory} instance using the given {@link RedisElastiCacheConfiguration}
* and {@link LettuceClientConfiguration}.
* Constructs a new {@link LettuceConnectionFactory} instance using the given
* {@link RedisStaticMasterSlaveConfiguration} and {@link LettuceClientConfiguration}.
*
* @param elastiCacheConfiguration must not be {@literal null}.
* @param redisConfiguration must not be {@literal null}.
* @param clientConfig must not be {@literal null}.
* @since 2.1
*/
public LettuceConnectionFactory(RedisElastiCacheConfiguration elastiCacheConfiguration,
LettuceClientConfiguration clientConfig) {
public LettuceConnectionFactory(RedisConfiguration redisConfiguration, LettuceClientConfiguration clientConfig) {
this(clientConfig);
Assert.notNull(elastiCacheConfiguration, "RedisElastiCacheConfiguration must not be null!");
Assert.notNull(redisConfiguration, "RedisConfiguration must not be null!");
this.elastiCacheConfiguration = elastiCacheConfiguration;
}
/**
* Constructs a new {@link LettuceConnectionFactory} instance using the given {@link RedisSocketConfiguration} and
* {@link LettuceClientConfiguration}.
*
* @param socketConfiguration must not be {@literal null}.
* @param clientConfig must not be {@literal null}.
* @since 2.1
*/
public LettuceConnectionFactory(RedisSocketConfiguration socketConfiguration,
LettuceClientConfiguration clientConfig) {
this(clientConfig);
Assert.notNull(socketConfiguration, "RedisSocketConfiguration must not be null!");
this.socketConfiguration = socketConfiguration;
this.configuration = redisConfiguration;
}
/**
@@ -253,7 +241,7 @@ public class LettuceConnectionFactory
Assert.notNull(sentinelConfiguration, "RedisSentinelConfiguration must not be null!");
this.sentinelConfiguration = sentinelConfiguration;
this.configuration = sentinelConfiguration;
}
/**
@@ -271,7 +259,7 @@ public class LettuceConnectionFactory
Assert.notNull(clusterConfiguration, "RedisClusterConfiguration must not be null!");
this.clusterConfiguration = clusterConfiguration;
this.configuration = clusterConfiguration;
}
/*
@@ -645,20 +633,7 @@ public class LettuceConnectionFactory
* @return the database index.
*/
public int getDatabase() {
if (isElastiCacheAware()) {
return elastiCacheConfiguration.getDatabase();
}
if (isDomainSocketAware()) {
return socketConfiguration.getDatabase();
}
if (isRedisSentinelAware()) {
return sentinelConfiguration.getDatabase();
}
return standaloneConfig.getDatabase();
return RedisConfiguration.getDatabaseOrElse(configuration, standaloneConfig::getDatabase);
}
/**
@@ -670,18 +645,9 @@ public class LettuceConnectionFactory
Assert.isTrue(index >= 0, "invalid DB index (a positive index required)");
if (isElastiCacheAware()) {
elastiCacheConfiguration.setDatabase(index);
return;
}
if (RedisConfiguration.isDatabaseIndexAware(configuration)) {
if (isDomainSocketAware()) {
socketConfiguration.setDatabase(index);
return;
}
if (isRedisSentinelAware()) {
sentinelConfiguration.setDatabase(index);
((WithDatabaseIndex) configuration).setDatabase(index);
return;
}
@@ -723,24 +689,7 @@ public class LettuceConnectionFactory
}
private RedisPassword getRedisPassword() {
if (isElastiCacheAware()) {
return elastiCacheConfiguration.getPassword();
}
if (isDomainSocketAware()) {
return socketConfiguration.getPassword();
}
if (isRedisSentinelAware()) {
return sentinelConfiguration.getPassword();
}
if (isClusterAware()) {
return clusterConfiguration.getPassword();
}
return standaloneConfig.getPassword();
return RedisConfiguration.getPasswordOrElse(configuration, standaloneConfig::getPassword);
}
/**
@@ -753,23 +702,9 @@ public class LettuceConnectionFactory
@Deprecated
public void setPassword(String password) {
if (isDomainSocketAware()) {
socketConfiguration.setPassword(RedisPassword.of(password));
return;
}
if (RedisConfiguration.isPasswordAware(configuration)) {
if (isElastiCacheAware()) {
elastiCacheConfiguration.setPassword(RedisPassword.of(password));
return;
}
if (isRedisSentinelAware()) {
sentinelConfiguration.setPassword(RedisPassword.of(password));
return;
}
if (isClusterAware()) {
clusterConfiguration.setPassword(RedisPassword.of(password));
((WithPassword) configuration).setPassword(password);
return;
}
@@ -845,7 +780,7 @@ public class LettuceConnectionFactory
*/
@Nullable
public RedisSocketConfiguration getSocketConfiguration() {
return socketConfiguration;
return isDomainSocketAware() ? (RedisSocketConfiguration) configuration : null;
}
/**
@@ -854,7 +789,7 @@ public class LettuceConnectionFactory
*/
@Nullable
public RedisSentinelConfiguration getSentinelConfiguration() {
return sentinelConfiguration;
return isRedisSentinelAware() ? (RedisSentinelConfiguration) configuration : null;
}
/**
@@ -863,7 +798,7 @@ public class LettuceConnectionFactory
*/
@Nullable
public RedisClusterConfiguration getClusterConfiguration() {
return clusterConfiguration;
return isClusterAware() ? (RedisClusterConfiguration) configuration : null;
}
/**
@@ -889,11 +824,11 @@ public class LettuceConnectionFactory
}
/**
* @return true when {@link RedisElastiCacheConfiguration} is present.
* @return true when {@link RedisStaticMasterSlaveConfiguration} is present.
* @since 2.1
*/
private boolean isElastiCacheAware() {
return elastiCacheConfiguration != null;
private boolean isStaticMasterSlaveAware() {
return RedisConfiguration.isStaticMasterSlaveConfiguration(configuration);
}
/**
@@ -901,7 +836,7 @@ public class LettuceConnectionFactory
* @since 1.5
*/
public boolean isRedisSentinelAware() {
return sentinelConfiguration != null;
return RedisConfiguration.isSentinelConfiguration(configuration);
}
/**
@@ -909,7 +844,7 @@ public class LettuceConnectionFactory
* @since 2.1
*/
private boolean isDomainSocketAware() {
return socketConfiguration != null;
return RedisConfiguration.isDomainSocketConfiguration(configuration);
}
/**
@@ -917,7 +852,7 @@ public class LettuceConnectionFactory
* @since 1.7
*/
public boolean isClusterAware() {
return clusterConfiguration != null;
return RedisConfiguration.isClusterConfiguration(configuration);
}
/**
@@ -967,14 +902,14 @@ public class LettuceConnectionFactory
ReadFrom readFrom = getClientConfiguration().getReadFrom().orElse(null);
if (isElastiCacheAware()) {
if (isStaticMasterSlaveAware()) {
List<RedisURI> nodes = this.elastiCacheConfiguration.getNodes().stream() //
List<RedisURI> nodes = ((RedisStaticMasterSlaveConfiguration) configuration).getNodes().stream() //
.map(it -> createRedisURIAndApplySettings(it.getHostName(), it.getPort())) //
.peek(it -> it.setDatabase(getDatabase())) //
.collect(Collectors.toList());
return new ElastiCacheConnectionProvider((RedisClient) client, codec, nodes, readFrom);
return new StaticMasterSlaveConnectionProvider((RedisClient) client, codec, nodes, readFrom);
}
if (isClusterAware()) {
@@ -986,7 +921,7 @@ public class LettuceConnectionFactory
protected AbstractRedisClient createClient() {
if (isElastiCacheAware()) {
if (isStaticMasterSlaveAware()) {
RedisClient redisClient = clientConfiguration.getClientResources() //
.map(RedisClient::create) //
@@ -1011,7 +946,7 @@ public class LettuceConnectionFactory
if (isClusterAware()) {
List<RedisURI> initialUris = new ArrayList<>();
for (RedisNode node : this.clusterConfiguration.getClusterNodes()) {
for (RedisNode node : ((ClusterConfiguration) configuration).getClusterNodes()) {
initialUris.add(createRedisURIAndApplySettings(node.getHost(), node.getPort()));
}
@@ -1026,7 +961,8 @@ public class LettuceConnectionFactory
return clusterClient;
}
RedisURI uri = isDomainSocketAware() ? createRedisSocketURIAndApplySettings(socketConfiguration.getSocket())
RedisURI uri = isDomainSocketAware()
? createRedisSocketURIAndApplySettings(((DomainSocketConfiguration) configuration).getSocket())
: createRedisURIAndApplySettings(getHostName(), getPort());
RedisClient redisClient = clientConfiguration.getClientResources() //
@@ -1039,7 +975,8 @@ public class LettuceConnectionFactory
private RedisURI getSentinelRedisURI() {
RedisURI redisUri = LettuceConverters.sentinelConfigurationToRedisURI(sentinelConfiguration);
RedisURI redisUri = LettuceConverters
.sentinelConfigurationToRedisURI((org.springframework.data.redis.connection.RedisSentinelConfiguration) configuration);
getRedisPassword().toOptional().ifPresent(redisUri::setPassword);
clientConfiguration.getClientName().ifPresent(redisUri::setClientName);

View File

@@ -29,13 +29,15 @@ import java.util.Optional;
import org.springframework.lang.Nullable;
/**
* {@link LettuceConnectionProvider} implementation for a AWS ElastiCache with replicas setup. <br/>
* {@link LettuceConnectionProvider} implementation for a static Master/Slave connection suitable for eg. AWS
* ElastiCache with replicas setup.<br/>
* Lettuce auto-discovers node roles from the static {@link RedisURI} collection.
*
* @author Mark Paluch
* @author Christoph Strobl
* @since 2.1
*/
class ElastiCacheConnectionProvider implements LettuceConnectionProvider {
class StaticMasterSlaveConnectionProvider implements LettuceConnectionProvider {
private final RedisClient client;
private final RedisCodec<?, ?> codec;
@@ -43,14 +45,14 @@ class ElastiCacheConnectionProvider implements LettuceConnectionProvider {
private final Collection<RedisURI> nodes;
/**
* Create new {@link ElastiCacheConnectionProvider}.
* Create new {@link StaticMasterSlaveConnectionProvider}.
*
* @param client must not be {@literal null}.
* @param codec must not be {@literal null}.
* @param nodes must not be {@literal null}.
* @param readFrom can be {@literal null}.
*/
ElastiCacheConnectionProvider(RedisClient client, RedisCodec<?, ?> codec, Collection<RedisURI> nodes,
StaticMasterSlaveConnectionProvider(RedisClient client, RedisCodec<?, ?> codec, Collection<RedisURI> nodes,
@Nullable ReadFrom readFrom) {
this.client = client;
@@ -74,6 +76,6 @@ class ElastiCacheConnectionProvider implements LettuceConnectionProvider {
return connectionType.cast(connection);
}
throw new UnsupportedOperationException("Connection type " + connectionType + " not supported!");
throw new UnsupportedOperationException(String.format("Connection type %s not supported!", connectionType));
}
}