Polishing.

Reorder methods. Remove unnecessary null guards. Introduce hashCode/equals methods to RedisConfiguration implementations. Refactor tests. Let LettuceClientConfiguration.builder apply settings from RedisURI. Introduce SentinelMasterId to implement equals method.

See #2116.
Original pull request: #2117.
This commit is contained in:
Mark Paluch
2021-07-13 16:19:43 +02:00
parent 19e9e7483b
commit 3286d57691
14 changed files with 550 additions and 252 deletions

View File

@@ -31,6 +31,7 @@ import org.springframework.data.redis.connection.RedisConfiguration.ClusterConfi
import org.springframework.lang.Nullable;
import org.springframework.util.Assert;
import org.springframework.util.NumberUtils;
import org.springframework.util.ObjectUtils;
import org.springframework.util.StringUtils;
/**
@@ -223,6 +224,44 @@ public class RedisClusterConfiguration implements RedisConfiguration, ClusterCon
this.password = password;
}
/*
* (non-Javadoc)
* @see java.lang.Object#equals(java.lang.Object)
*/
@Override
public boolean equals(Object o) {
if (this == o) {
return true;
}
if (!(o instanceof RedisClusterConfiguration)) {
return false;
}
RedisClusterConfiguration that = (RedisClusterConfiguration) o;
if (!ObjectUtils.nullSafeEquals(clusterNodes, that.clusterNodes)) {
return false;
}
if (!ObjectUtils.nullSafeEquals(maxRedirects, that.maxRedirects)) {
return false;
}
if (!ObjectUtils.nullSafeEquals(username, that.username)) {
return false;
}
return ObjectUtils.nullSafeEquals(password, that.password);
}
/*
* (non-Javadoc)
* @see java.lang.Object#hashCode()
*/
@Override
public int hashCode() {
int result = ObjectUtils.nullSafeHashCode(clusterNodes);
result = 31 * result + ObjectUtils.nullSafeHashCode(maxRedirects);
result = 31 * result + ObjectUtils.nullSafeHashCode(username);
result = 31 * result + ObjectUtils.nullSafeHashCode(password);
return result;
}
private RedisNode readHostAndPortFromString(String hostAndPort) {
String[] args = split(hostAndPort, ":");

View File

@@ -349,11 +349,11 @@ public interface RedisConfiguration {
*
* @param name must not be {@literal null}.
*/
default void setMaster(final String name) {
default void setMaster(String name) {
Assert.notNull(name, "Name of sentinel master must not be null.");
setMaster(() -> name);
setMaster(new SentinelMasterId(name));
}
/**

View File

@@ -28,6 +28,7 @@ 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.ObjectUtils;
import org.springframework.util.StringUtils;
/**
@@ -289,6 +290,52 @@ public class RedisSentinelConfiguration implements RedisConfiguration, SentinelC
return sentinelPassword;
}
/*
* (non-Javadoc)
* @see java.lang.Object#equals(java.lang.Object)
*/
@Override
public boolean equals(Object o) {
if (this == o) {
return true;
}
if (!(o instanceof RedisSentinelConfiguration)) {
return false;
}
RedisSentinelConfiguration that = (RedisSentinelConfiguration) o;
if (database != that.database) {
return false;
}
if (!ObjectUtils.nullSafeEquals(master, that.master)) {
return false;
}
if (!ObjectUtils.nullSafeEquals(sentinels, that.sentinels)) {
return false;
}
if (!ObjectUtils.nullSafeEquals(dataNodeUsername, that.dataNodeUsername)) {
return false;
}
if (!ObjectUtils.nullSafeEquals(dataNodePassword, that.dataNodePassword)) {
return false;
}
return ObjectUtils.nullSafeEquals(sentinelPassword, that.sentinelPassword);
}
/*
* (non-Javadoc)
* @see java.lang.Object#hashCode()
*/
@Override
public int hashCode() {
int result = ObjectUtils.nullSafeHashCode(master);
result = 31 * result + ObjectUtils.nullSafeHashCode(sentinels);
result = 31 * result + database;
result = 31 * result + ObjectUtils.nullSafeHashCode(dataNodeUsername);
result = 31 * result + ObjectUtils.nullSafeHashCode(dataNodePassword);
result = 31 * result + ObjectUtils.nullSafeHashCode(sentinelPassword);
return result;
}
private RedisNode readHostAndPortFromString(String hostAndPort) {
String[] args = split(hostAndPort, ":");

View File

@@ -18,6 +18,7 @@ package org.springframework.data.redis.connection;
import org.springframework.data.redis.connection.RedisConfiguration.DomainSocketConfiguration;
import org.springframework.lang.Nullable;
import org.springframework.util.Assert;
import org.springframework.util.ObjectUtils;
/**
* Configuration class used for setting up {@link RedisConnection} via {@link RedisConnectionFactory} connecting to
@@ -133,4 +134,42 @@ public class RedisSocketConfiguration implements RedisConfiguration, DomainSocke
this.password = password;
}
/*
* (non-Javadoc)
* @see java.lang.Object#equals(java.lang.Object)
*/
@Override
public boolean equals(Object o) {
if (this == o) {
return true;
}
if (!(o instanceof RedisSocketConfiguration)) {
return false;
}
RedisSocketConfiguration that = (RedisSocketConfiguration) o;
if (database != that.database) {
return false;
}
if (!ObjectUtils.nullSafeEquals(socket, that.socket)) {
return false;
}
if (!ObjectUtils.nullSafeEquals(username, that.username)) {
return false;
}
return ObjectUtils.nullSafeEquals(password, that.password);
}
/*
* (non-Javadoc)
* @see java.lang.Object#hashCode()
*/
@Override
public int hashCode() {
int result = ObjectUtils.nullSafeHashCode(socket);
result = 31 * result + database;
result = 31 * result + ObjectUtils.nullSafeHashCode(username);
result = 31 * result + ObjectUtils.nullSafeHashCode(password);
return result;
}
}

View File

@@ -20,6 +20,7 @@ import org.springframework.data.redis.connection.RedisConfiguration.WithHostAndP
import org.springframework.data.redis.connection.RedisConfiguration.WithPassword;
import org.springframework.lang.Nullable;
import org.springframework.util.Assert;
import org.springframework.util.ObjectUtils;
/**
* Configuration class used for setting up {@link RedisConnection} via {@link RedisConnectionFactory} using connecting
@@ -166,4 +167,46 @@ public class RedisStandaloneConfiguration
this.password = password;
}
/*
* (non-Javadoc)
* @see java.lang.Object#equals(java.lang.Object)
*/
@Override
public boolean equals(Object o) {
if (this == o) {
return true;
}
if (!(o instanceof RedisStandaloneConfiguration)) {
return false;
}
RedisStandaloneConfiguration that = (RedisStandaloneConfiguration) o;
if (port != that.port) {
return false;
}
if (database != that.database) {
return false;
}
if (!ObjectUtils.nullSafeEquals(hostName, that.hostName)) {
return false;
}
if (!ObjectUtils.nullSafeEquals(username, that.username)) {
return false;
}
return ObjectUtils.nullSafeEquals(password, that.password);
}
/*
* (non-Javadoc)
* @see java.lang.Object#hashCode()
*/
@Override
public int hashCode() {
int result = ObjectUtils.nullSafeHashCode(hostName);
result = 31 * result + port;
result = 31 * result + database;
result = 31 * result + ObjectUtils.nullSafeHashCode(username);
result = 31 * result + ObjectUtils.nullSafeHashCode(password);
return result;
}
}

View File

@@ -22,6 +22,7 @@ import java.util.List;
import org.springframework.data.redis.connection.RedisConfiguration.StaticMasterReplicaConfiguration;
import org.springframework.lang.Nullable;
import org.springframework.util.Assert;
import org.springframework.util.ObjectUtils;
/**
* Configuration class used for setting up {@link RedisConnection} via {@link RedisConnectionFactory} using the provided
@@ -181,4 +182,42 @@ public class RedisStaticMasterReplicaConfiguration implements RedisConfiguration
public List<RedisStandaloneConfiguration> getNodes() {
return Collections.unmodifiableList(nodes);
}
/*
* (non-Javadoc)
* @see java.lang.Object#equals(java.lang.Object)
*/
@Override
public boolean equals(Object o) {
if (this == o) {
return true;
}
if (!(o instanceof RedisStaticMasterReplicaConfiguration)) {
return false;
}
RedisStaticMasterReplicaConfiguration that = (RedisStaticMasterReplicaConfiguration) o;
if (database != that.database) {
return false;
}
if (!ObjectUtils.nullSafeEquals(nodes, that.nodes)) {
return false;
}
if (!ObjectUtils.nullSafeEquals(username, that.username)) {
return false;
}
return ObjectUtils.nullSafeEquals(password, that.password);
}
/*
* (non-Javadoc)
* @see java.lang.Object#hashCode()
*/
@Override
public int hashCode() {
int result = ObjectUtils.nullSafeHashCode(nodes);
result = 31 * result + database;
result = 31 * result + ObjectUtils.nullSafeHashCode(username);
result = 31 * result + ObjectUtils.nullSafeHashCode(password);
return result;
}
}

View File

@@ -0,0 +1,80 @@
/*
* Copyright 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.data.redis.connection;
import org.springframework.lang.NonNull;
import org.springframework.util.Assert;
import org.springframework.util.ObjectUtils;
/**
* Simple {@link NamedNode}.
*
* @author Mark Paluch
* @since 2.5.3
*/
class SentinelMasterId implements NamedNode {
private final String name;
public SentinelMasterId(String name) {
Assert.hasText(name, "Sentinel Master Id must not be null or empty");
this.name = name;
}
/*
* (non-Javadoc)
* @see org.springframework.data.redis.connection.NamedNode#getName()
*/
@NonNull
@Override
public String getName() {
return name;
}
/*
* (non-Javadoc)
* @see java.lang.Object#toString()
*/
@Override
public String toString() {
return getName();
}
/*
* (non-Javadoc)
* @see java.lang.Object#equals(java.lang.Object)
*/
@Override
public boolean equals(Object o) {
if (this == o) {
return true;
}
if (!(o instanceof SentinelMasterId)) {
return false;
}
SentinelMasterId that = (SentinelMasterId) o;
return ObjectUtils.nullSafeEquals(name, that.name);
}
/*
* (non-Javadoc)
* @see java.lang.Object#hashCode()
*/
@Override
public int hashCode() {
return ObjectUtils.nullSafeHashCode(name);
}
}

View File

@@ -27,6 +27,7 @@ import java.util.concurrent.TimeUnit;
import org.springframework.lang.Nullable;
import org.springframework.util.Assert;
import org.springframework.util.ObjectUtils;
/**
* Redis client configuration for lettuce. This configuration provides optional configuration elements such as
@@ -173,6 +174,30 @@ public interface LettuceClientConfiguration {
LettuceClientConfigurationBuilder() {}
/**
* Apply SSL settings, command timeout, and client name from a {@link RedisURI}.
*
* @param redisUri the connection URI.
* @return {@literal this} builder.
* @since 2.5.3
*/
public LettuceClientConfigurationBuilder apply(RedisURI redisUri) {
this.useSsl = redisUri.isSsl();
this.verifyPeer = redisUri.isVerifyPeer();
this.startTls = redisUri.isStartTls();
if (!redisUri.getTimeout().equals(RedisURI.DEFAULT_TIMEOUT_DURATION)) {
this.timeout = redisUri.getTimeout();
}
if (!ObjectUtils.isEmpty(redisUri.getClientName())) {
this.clientName = redisUri.getClientName();
}
return this;
}
/**
* Enable SSL connections.
*

View File

@@ -282,29 +282,51 @@ public class LettuceConnectionFactory
}
/**
* Creates a {@link RedisConfiguration} based on a {@link RedisURI} according to the following:
* Creates a {@link RedisConfiguration} based on a {@link String URI} according to the following:
* <ul>
* <li>If {@code redisURI} has sentinel info a {@link RedisSentinelConfiguration} is returned</li>
* <li>If {@code redisURI} has socket info a {@link RedisSocketConfiguration} is returned</li>
* <li>If {@code redisUri} contains sentinels, a {@link RedisSentinelConfiguration} is returned</li>
* <li>If {@code redisUri} has a configured socket a {@link RedisSocketConfiguration} is returned</li>
* <li>Otherwise a {@link RedisStandaloneConfiguration} is returned</li>
* </ul>
*
* @param redisURI the connection info in the format of a RedisURI
* @param redisUri the connection URI in the format of a {@link RedisURI}.
* @return an appropriate {@link RedisConfiguration} instance representing the Redis URI.
* @since 2.5.3
* @see RedisURI
*/
public static RedisConfiguration createRedisConfiguration(RedisURI redisURI) {
public static RedisConfiguration createRedisConfiguration(String redisUri) {
Assert.notNull(redisURI, "RedisURI must not be null");
Assert.hasText(redisUri, "RedisURI must not be null and not empty");
if (!ObjectUtils.isEmpty(redisURI.getSentinels())) {
return LettuceConverters.redisUriToSentinelConfiguration(redisURI);
return createRedisConfiguration(RedisURI.create(redisUri));
}
/**
* Creates a {@link RedisConfiguration} based on a {@link RedisURI} according to the following:
* <ul>
* <li>If {@link RedisURI} contains sentinels, a {@link RedisSentinelConfiguration} is returned</li>
* <li>If {@link RedisURI} has a configured socket a {@link RedisSocketConfiguration} is returned</li>
* <li>Otherwise a {@link RedisStandaloneConfiguration} is returned</li>
* </ul>
*
* @param redisUri the connection URI.
* @return an appropriate {@link RedisConfiguration} instance representing the Redis URI.
* @since 2.5.3
* @see RedisURI
*/
public static RedisConfiguration createRedisConfiguration(RedisURI redisUri) {
Assert.notNull(redisUri, "RedisURI must not be null");
if (!ObjectUtils.isEmpty(redisUri.getSentinels())) {
return LettuceConverters.createRedisSentinelConfiguration(redisUri);
}
if (!ObjectUtils.isEmpty(redisURI.getSocket())) {
return LettuceConverters.redisUriToSocketConfiguration(redisURI);
if (!ObjectUtils.isEmpty(redisUri.getSocket())) {
return LettuceConverters.createRedisSocketConfiguration(redisUri);
}
return LettuceConverters.redisUriToStandaloneConfiguration(redisURI);
return LettuceConverters.createRedisStandaloneConfiguration(redisUri);
}
/*

View File

@@ -527,16 +527,51 @@ public abstract class LettuceConverters extends Converters {
return builder.build();
}
/**
* Converts a {@link RedisURI} to its corresponding {@link RedisStandaloneConfiguration}.
*
* @param redisURI the uri containing the Redis connection info
* @return a {@link RedisStandaloneConfiguration} representing the connection information in the Redis URI.
* @since 2.5.3
*/
static RedisStandaloneConfiguration createRedisStandaloneConfiguration(RedisURI redisURI) {
RedisStandaloneConfiguration standaloneConfiguration = new RedisStandaloneConfiguration();
standaloneConfiguration.setHostName(redisURI.getHost());
standaloneConfiguration.setPort(redisURI.getPort());
standaloneConfiguration.setDatabase(redisURI.getDatabase());
applyAuthentication(redisURI, standaloneConfiguration);
return standaloneConfiguration;
}
/**
* Converts a {@link RedisURI} to its corresponding {@link RedisSocketConfiguration}.
*
* @param redisURI the uri containing the Redis connection info using a local unix domain socket
* @return a {@link RedisSocketConfiguration} representing the connection information in the Redis URI.
* @since 2.5.3
*/
static RedisSocketConfiguration createRedisSocketConfiguration(RedisURI redisURI) {
RedisSocketConfiguration socketConfiguration = new RedisSocketConfiguration();
socketConfiguration.setSocket(redisURI.getSocket());
socketConfiguration.setDatabase(redisURI.getDatabase());
applyAuthentication(redisURI, socketConfiguration);
return socketConfiguration;
}
/**
* Converts a {@link RedisURI} to its corresponding {@link RedisSentinelConfiguration}.
*
* @param redisURI the uri containing the Redis Sentinel connection info
* @return a {@link RedisSentinelConfiguration} representing the Redis Sentinel information in the Redis URI.
* @since 2.6
* @since 2.5.3
*/
static RedisSentinelConfiguration redisUriToSentinelConfiguration(RedisURI redisURI) {
Assert.notNull(redisURI, "RedisURI is required");
static RedisSentinelConfiguration createRedisSentinelConfiguration(RedisURI redisURI) {
RedisSentinelConfiguration sentinelConfiguration = new RedisSentinelConfiguration();
if (!ObjectUtils.isEmpty(redisURI.getSentinelMasterId())) {
@@ -557,51 +592,12 @@ public abstract class LettuceConverters extends Converters {
return sentinelConfiguration;
}
/**
* Converts a {@link RedisURI} to its corresponding {@link RedisSocketConfiguration}.
*
* @param redisURI the uri containing the Redis connection info using a local unix domain socket
* @return a {@link RedisSocketConfiguration} representing the connection information in the Redis URI.
* @since 2.6
*/
static RedisSocketConfiguration redisUriToSocketConfiguration(RedisURI redisURI) {
Assert.notNull(redisURI, "RedisURI is required");
RedisSocketConfiguration socketConfiguration = new RedisSocketConfiguration();
socketConfiguration.setSocket(redisURI.getSocket());
socketConfiguration.setDatabase(redisURI.getDatabase());
applyAuthentication(redisURI, socketConfiguration);
return socketConfiguration;
}
/**
* Converts a {@link RedisURI} to its corresponding {@link RedisStandaloneConfiguration}.
*
* @param redisURI the uri containing the Redis connection info
* @return a {@link RedisStandaloneConfiguration} representing the connection information in the Redis URI.
* @since 2.6
*/
static RedisStandaloneConfiguration redisUriToStandaloneConfiguration(RedisURI redisURI) {
Assert.notNull(redisURI, "RedisURI is required");
RedisStandaloneConfiguration standaloneConfiguration = new RedisStandaloneConfiguration();
standaloneConfiguration.setHostName(redisURI.getHost());
standaloneConfiguration.setPort(redisURI.getPort());
standaloneConfiguration.setDatabase(redisURI.getDatabase());
applyAuthentication(redisURI, standaloneConfiguration);
return standaloneConfiguration;
}
private static void applyAuthentication(RedisURI redisURI, RedisConfiguration.WithAuthentication redisConfiguration) {
if (StringUtils.hasText(redisURI.getUsername())) {
redisConfiguration.setUsername(redisURI.getUsername());
}
if (redisURI.getPassword() != null) {
redisConfiguration.setPassword(redisURI.getPassword());
}