diff --git a/src/main/java/org/springframework/data/redis/connection/jedis/JedisConnection.java b/src/main/java/org/springframework/data/redis/connection/jedis/JedisConnection.java index 22ab9a0b3..7b5901052 100644 --- a/src/main/java/org/springframework/data/redis/connection/jedis/JedisConnection.java +++ b/src/main/java/org/springframework/data/redis/connection/jedis/JedisConnection.java @@ -15,15 +15,7 @@ */ package org.springframework.data.redis.connection.jedis; -import redis.clients.jedis.BinaryJedis; -import redis.clients.jedis.BinaryJedisPubSub; -import redis.clients.jedis.Client; -import redis.clients.jedis.Connection; -import redis.clients.jedis.Jedis; -import redis.clients.jedis.MultiKeyPipelineBase; -import redis.clients.jedis.Pipeline; -import redis.clients.jedis.Response; -import redis.clients.jedis.Transaction; +import redis.clients.jedis.*; import redis.clients.jedis.exceptions.JedisDataException; import redis.clients.jedis.util.Pool; @@ -49,7 +41,6 @@ import org.springframework.data.redis.connection.jedis.JedisResult.JedisStatusRe import org.springframework.lang.Nullable; import org.springframework.util.Assert; import org.springframework.util.CollectionUtils; -import org.springframework.util.StringUtils; /** * {@code RedisConnection} implementation on top of Jedis library. @@ -81,6 +72,8 @@ public class JedisConnection extends AbstractRedisConnection { private final @Nullable Pool pool; private final String clientName; + private final JedisClientConfig nodeConfig; + private final JedisClientConfig sentinelConfig; private List pipelinedResults = new ArrayList<>(); private Queue>> txResults = new LinkedList<>(); @@ -120,18 +113,38 @@ public class JedisConnection extends AbstractRedisConnection { * @param clientName the client name, can be {@literal null}. * @since 1.8 */ - protected JedisConnection(Jedis jedis, @Nullable Pool pool, int dbIndex, String clientName) { + protected JedisConnection(Jedis jedis, @Nullable Pool pool, int dbIndex, @Nullable String clientName) { + this(jedis, pool, createConfig(dbIndex, clientName), createConfig(dbIndex, clientName)); + } + + private static DefaultJedisClientConfig createConfig(int dbIndex, @Nullable String clientName) { + return DefaultJedisClientConfig.builder().databse(dbIndex).clientName(clientName).build(); + } + + /** + * Constructs a new JedisConnection instance backed by a jedis pool. + * + * @param jedis + * @param pool can be null, if no pool is used + * @param nodeConfig node configuration + * @param sentinelConfig sentinel configuration + * @since 2.5 + */ + protected JedisConnection(Jedis jedis, @Nullable Pool pool, JedisClientConfig nodeConfig, + JedisClientConfig sentinelConfig) { this.jedis = jedis; this.pool = pool; - this.clientName = clientName; + this.clientName = nodeConfig.getClientName(); + this.nodeConfig = nodeConfig; + this.sentinelConfig = sentinelConfig; // select the db // if this fail, do manual clean-up before propagating the exception // as we're inside the constructor - if (dbIndex != jedis.getDB()) { + if (nodeConfig.getDatabase() != jedis.getDB()) { try { - select(dbIndex); + select(nodeConfig.getDatabase()); } catch (DataAccessException ex) { close(); throw ex; @@ -776,14 +789,7 @@ public class JedisConnection extends AbstractRedisConnection { } protected Jedis getJedis(RedisNode node) { - - Jedis jedis = new Jedis(node.getHost(), node.getPort()); - - if (StringUtils.hasText(clientName)) { - jedis.clientSetname(clientName); - } - - return jedis; + return new Jedis(new HostAndPort(node.getHost(), node.getPort()), this.sentinelConfig); } @Nullable 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 e6ea59b1d..809962fbb 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 @@ -15,9 +15,10 @@ */ package org.springframework.data.redis.connection.jedis; -import redis.clients.jedis.Client; +import redis.clients.jedis.DefaultJedisClientConfig; import redis.clients.jedis.HostAndPort; import redis.clients.jedis.Jedis; +import redis.clients.jedis.JedisClientConfig; import redis.clients.jedis.JedisCluster; import redis.clients.jedis.JedisPool; import redis.clients.jedis.JedisPoolConfig; @@ -41,6 +42,7 @@ import javax.net.ssl.SSLSocketFactory; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.apache.commons.pool2.impl.GenericObjectPoolConfig; + import org.springframework.beans.factory.DisposableBean; import org.springframework.beans.factory.InitializingBean; import org.springframework.dao.DataAccessException; @@ -58,6 +60,7 @@ import org.springframework.lang.Nullable; import org.springframework.util.Assert; import org.springframework.util.ClassUtils; import org.springframework.util.CollectionUtils; +import org.springframework.util.ObjectUtils; import org.springframework.util.StringUtils; /** @@ -88,6 +91,7 @@ public class JedisConnectionFactory implements InitializingBean, DisposableBean, private final JedisClientConfiguration clientConfiguration; private @Nullable JedisShardInfo shardInfo; + private JedisClientConfig clientConfig = DefaultJedisClientConfig.builder().build(); private boolean providedShardInfo = false; private @Nullable Pool pool; private boolean convertPipelineAndTxResults = true; @@ -290,17 +294,7 @@ public class JedisConnectionFactory implements InitializingBean, DisposableBean, return new Jedis(getShardInfo()); } - Jedis jedis = new Jedis(getHostName(), getPort(), getConnectTimeout(), getReadTimeout(), isUseSsl(), - clientConfiguration.getSslSocketFactory().orElse(null), // - clientConfiguration.getSslParameters().orElse(null), // - clientConfiguration.getHostnameVerifier().orElse(null)); - - Client client = jedis.getClient(); - - getRedisPassword().map(String::new).ifPresent(client::setPassword); - client.setDb(getDatabase()); - - return jedis; + return new Jedis(new HostAndPort(getHostName(), getPort()), this.clientConfig); } /** @@ -320,6 +314,8 @@ public class JedisConnectionFactory implements InitializingBean, DisposableBean, */ public void afterPropertiesSet() { + clientConfig = createClientConfig(getRedisUsername(), getRedisPassword()); + if (shardInfo == null && clientConfiguration instanceof MutableJedisClientConfiguration) { providedShardInfo = false; @@ -357,6 +353,33 @@ public class JedisConnectionFactory implements InitializingBean, DisposableBean, } } + private JedisClientConfig createClientConfig(@Nullable String username, RedisPassword password) { + + DefaultJedisClientConfig.Builder builder = DefaultJedisClientConfig.builder(); + + clientConfiguration.getClientName().ifPresent(builder::clientName); + builder.connectionTimeoutMillis(getConnectTimeout()); + builder.socketTimeoutMillis(getReadTimeout()); + + builder.databse(getDatabase()); + + if (!ObjectUtils.isEmpty(username)) { + builder.user(username); + } + password.toOptional().map(String::new).ifPresent(builder::password); + + if (isUseSsl()) { + + builder.ssl(true); + + clientConfiguration.getSslSocketFactory().ifPresent(builder::sslSocketFactory); + clientConfiguration.getHostnameVerifier().ifPresent(builder::hostnameVerifier); + clientConfiguration.getSslParameters().ifPresent(builder::sslParameters); + } + + return builder.build(); + } + private Pool createPool() { if (isRedisSentinelAware()) { @@ -374,13 +397,12 @@ public class JedisConnectionFactory implements InitializingBean, DisposableBean, */ protected Pool createRedisSentinelPool(RedisSentinelConfiguration config) { - GenericObjectPoolConfig poolConfig = getPoolConfig() != null ? getPoolConfig() : new JedisPoolConfig(); + GenericObjectPoolConfig poolConfig = getPoolConfig() != null ? getPoolConfig() : new JedisPoolConfig(); String sentinelUser = null; - String sentinelPassword = config.getSentinelPassword().toOptional().map(String::new).orElse(null); + JedisClientConfig sentinelConfig = createClientConfig(sentinelUser, config.getSentinelPassword()); return new JedisSentinelPool(config.getMaster().getName(), convertToJedisSentinelSet(config.getSentinels()), - poolConfig, getConnectTimeout(), getReadTimeout(), getUsername(), getPassword(), getDatabase(), getClientName(), - getConnectTimeout(), getReadTimeout(), sentinelUser, sentinelPassword, getClientName()); + poolConfig, this.clientConfig, sentinelConfig); } /** @@ -390,12 +412,7 @@ public class JedisConnectionFactory implements InitializingBean, DisposableBean, * @since 1.4 */ protected Pool createRedisPool() { - - return new JedisPool(getPoolConfig(), getHostName(), getPort(), getConnectTimeout(), getReadTimeout(), - getUsername(), getPassword(), getDatabase(), getClientName(), isUseSsl(), - clientConfiguration.getSslSocketFactory().orElse(null), // - clientConfiguration.getSslParameters().orElse(null), // - clientConfiguration.getHostnameVerifier().orElse(null)); + return new JedisPool(getPoolConfig(), new HostAndPort(getHostName(), getPort()), this.clientConfig); } private JedisCluster createCluster() { @@ -423,7 +440,8 @@ public class JedisConnectionFactory implements InitializingBean, DisposableBean, * @return the actual {@link JedisCluster}. * @since 1.7 */ - protected JedisCluster createCluster(RedisClusterConfiguration clusterConfig, GenericObjectPoolConfig poolConfig) { + protected JedisCluster createCluster(RedisClusterConfiguration clusterConfig, + GenericObjectPoolConfig poolConfig) { Assert.notNull(clusterConfig, "Cluster configuration must not be null!"); @@ -434,10 +452,7 @@ public class JedisConnectionFactory implements InitializingBean, DisposableBean, int redirects = clusterConfig.getMaxRedirects() != null ? clusterConfig.getMaxRedirects() : 5; - return new JedisCluster(hostAndPort, getConnectTimeout(), getReadTimeout(), redirects, getUsername(), getPassword(), - getClientName(), poolConfig, isUseSsl(), clientConfiguration.getSslSocketFactory().orElse(null), - clientConfiguration.getSslParameters().orElse(null), clientConfiguration.getHostnameVerifier().orElse(null), - null); + return new JedisCluster(hostAndPort, this.clientConfig, redirects, poolConfig); } /* @@ -553,16 +568,6 @@ public class JedisConnectionFactory implements InitializingBean, DisposableBean, getMutableConfiguration().setUseSsl(useSsl); } - /** - * Returns the username used for authenticating with the Redis server. - * - * @return username for authentication. - */ - @Nullable - private String getUsername() { - return getRedisUsername(); - } - /** * Returns the password used for authenticating with the Redis server. * @@ -715,7 +720,7 @@ public class JedisConnectionFactory implements InitializingBean, DisposableBean, * @return the poolConfig */ @Nullable - public GenericObjectPoolConfig getPoolConfig() { + public GenericObjectPoolConfig getPoolConfig() { return clientConfiguration.getPoolConfig().orElse(null); } @@ -877,35 +882,41 @@ public class JedisConnectionFactory implements InitializingBean, DisposableBean, Assert.isTrue(RedisConfiguration.isSentinelConfiguration(configuration), "SentinelConfig must not be null!"); SentinelConfiguration sentinelConfiguration = (SentinelConfiguration) configuration; + JedisClientConfig clientConfig = createClientConfig(null, sentinelConfiguration.getSentinelPassword()); for (RedisNode node : sentinelConfiguration.getSentinels()) { - Jedis jedis = new Jedis(node.getHost(), node.getPort(), getConnectTimeout(), getReadTimeout()); - sentinelConfiguration.getSentinelPassword().toOptional().map(String::new).ifPresent(jedis::auth); + Jedis jedis = null; + boolean success = false; try { - if (jedis.ping().equalsIgnoreCase("pong")) { - potentiallySetClientName(jedis); + jedis = new Jedis(new HostAndPort(node.getHost(), node.getPort()), clientConfig); + if (jedis.ping().equalsIgnoreCase("pong")) { + success = true; return jedis; } } catch (Exception ex) { log.warn(String.format("Ping failed for sentinel host:%s", node.getHost()), ex); + } finally { + if (!success && jedis != null) { + jedis.close(); + } } } throw new InvalidDataAccessResourceUsageException("No Sentinel found"); } - private Set convertToJedisSentinelSet(Collection nodes) { + private static Set convertToJedisSentinelSet(Collection nodes) { if (CollectionUtils.isEmpty(nodes)) { return Collections.emptySet(); } - Set convertedNodes = new LinkedHashSet<>(nodes.size()); + Set convertedNodes = new LinkedHashSet<>(nodes.size()); for (RedisNode node : nodes) { if (node != null) { - convertedNodes.add(node.asString()); + convertedNodes.add(new HostAndPort(node.getHost(), node.getPort())); } } return convertedNodes;