diff --git a/src/main/java/org/springframework/data/redis/connection/ReactiveRedisConnectionFactory.java b/src/main/java/org/springframework/data/redis/connection/ReactiveRedisConnectionFactory.java index e9bd578f9..af3eb469e 100644 --- a/src/main/java/org/springframework/data/redis/connection/ReactiveRedisConnectionFactory.java +++ b/src/main/java/org/springframework/data/redis/connection/ReactiveRedisConnectionFactory.java @@ -32,13 +32,15 @@ public interface ReactiveRedisConnectionFactory extends PersistenceExceptionTran /** * @return a reactive Redis connection. - * @since 2.0. + * @throws IllegalStateException if the connection factory requires initialization and the factory was not yet + * initialized. */ ReactiveRedisConnection getReactiveConnection(); /** * @return a reactive Redis Cluster connection. - * @since 2.0 + * @throws IllegalStateException if the connection factory requires initialization and the factory was not yet + * initialized. */ ReactiveRedisClusterConnection getReactiveClusterConnection(); } diff --git a/src/main/java/org/springframework/data/redis/connection/RedisConnectionFactory.java b/src/main/java/org/springframework/data/redis/connection/RedisConnectionFactory.java index bcc5d7f07..85cb649c3 100644 --- a/src/main/java/org/springframework/data/redis/connection/RedisConnectionFactory.java +++ b/src/main/java/org/springframework/data/redis/connection/RedisConnectionFactory.java @@ -30,6 +30,8 @@ public interface RedisConnectionFactory extends PersistenceExceptionTranslator { * Provides a suitable connection for interacting with Redis. * * @return connection for interacting with Redis. + * @throws IllegalStateException if the connection factory requires initialization and the factory was not yet + * initialized. */ RedisConnection getConnection(); @@ -37,6 +39,8 @@ public interface RedisConnectionFactory extends PersistenceExceptionTranslator { * Provides a suitable connection for interacting with Redis Cluster. * * @return + * @throws IllegalStateException if the connection factory requires initialization and the factory was not yet + * initialized. * @since 1.7 */ RedisClusterConnection getClusterConnection(); @@ -55,6 +59,8 @@ public interface RedisConnectionFactory extends PersistenceExceptionTranslator { * Provides a suitable connection for interacting with Redis Sentinel. * * @return connection for interacting with Redis Sentinel. + * @throws IllegalStateException if the connection factory requires initialization and the factory was not yet + * initialized. * @since 1.4 */ RedisSentinelConnection getSentinelConnection(); 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 397b4ab18..f09edff5a 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 @@ -73,6 +73,9 @@ import org.springframework.util.StringUtils; *
  • {@link RedisSentinelConfiguration}
  • *
  • {@link RedisClusterConfiguration}
  • * + *

    + * This connection factory must be {@link #afterPropertiesSet() initialized} prior to {@link #getConnection obtaining + * connections}. * * @author Costin Leau * @author Thomas Darimont @@ -104,6 +107,9 @@ public class JedisConnectionFactory implements InitializingBean, DisposableBean, private @Nullable ClusterTopologyProvider topologyProvider; private @Nullable ClusterCommandExecutor clusterCommandExecutor; + private boolean initialized; + private boolean destroyed; + /** * Constructs a new JedisConnectionFactory instance with default settings (default connection pooling, no * shard information). @@ -350,6 +356,8 @@ public class JedisConnectionFactory implements InitializingBean, DisposableBean, new JedisClusterConnection.JedisClusterNodeResourceProvider(this.cluster, this.topologyProvider), EXCEPTION_TRANSLATION); } + + this.initialized = true; } private JedisClientConfig createClientConfig(@Nullable String username, RedisPassword password) { @@ -484,6 +492,8 @@ public class JedisConnectionFactory implements InitializingBean, DisposableBean, log.warn("Cannot properly close cluster command executor", ex); } } + + this.destroyed = true; } /* @@ -492,6 +502,8 @@ public class JedisConnectionFactory implements InitializingBean, DisposableBean, */ public RedisConnection getConnection() { + assertInitialized(); + if (isRedisClusterAware()) { return getClusterConnection(); } @@ -517,6 +529,8 @@ public class JedisConnectionFactory implements InitializingBean, DisposableBean, @Override public RedisClusterConnection getClusterConnection() { + assertInitialized(); + if (!isRedisClusterAware()) { throw new InvalidDataAccessApiUsageException("Cluster is not configured!"); } @@ -876,6 +890,8 @@ public class JedisConnectionFactory implements InitializingBean, DisposableBean, @Override public RedisSentinelConnection getSentinelConnection() { + assertInitialized(); + if (!isRedisSentinelAware()) { throw new InvalidDataAccessResourceUsageException("No Sentinels configured"); } @@ -945,6 +961,11 @@ public class JedisConnectionFactory implements InitializingBean, DisposableBean, return (MutableJedisClientConfiguration) clientConfiguration; } + private void assertInitialized() { + Assert.state(this.initialized, "JedisConnectionFactory was not initialized through afterPropertiesSet()"); + Assert.state(!this.destroyed, "JedisConnectionFactory was destroyed and cannot be used anymore"); + } + /** * Mutable implementation of {@link JedisClientConfiguration}. * 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 5f2ab8cfc..e04f45bac 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 @@ -84,6 +84,9 @@ import org.springframework.util.StringUtils; *

  • {@link RedisSentinelConfiguration}
  • *
  • {@link RedisClusterConfiguration}
  • * + *

    + * This connection factory must be {@link #afterPropertiesSet() initialized} prior to {@link #getConnection obtaining + * connections}. * * @author Costin Leau * @author Jennifer Hickey @@ -124,6 +127,9 @@ public class LettuceConnectionFactory private @Nullable ClusterCommandExecutor clusterCommandExecutor; + private boolean initialized; + private boolean destroyed; + /** * Constructs a new {@link LettuceConnectionFactory} instance with default settings. */ @@ -293,6 +299,8 @@ public class LettuceConnectionFactory EXCEPTION_TRANSLATION); } + this.initialized = true; + if (getEagerInitialization() && getShareNativeConnection()) { initConnection(); } @@ -329,6 +337,8 @@ public class LettuceConnectionFactory log.warn("Cannot properly close cluster command executor", ex); } } + + this.destroyed = true; } private void dispose(LettuceConnectionProvider connectionProvider) { @@ -351,6 +361,8 @@ public class LettuceConnectionFactory */ public RedisConnection getConnection() { + assertInitialized(); + if (isClusterAware()) { return getClusterConnection(); } @@ -368,6 +380,8 @@ public class LettuceConnectionFactory @Override public RedisClusterConnection getClusterConnection() { + assertInitialized(); + if (!isClusterAware()) { throw new InvalidDataAccessApiUsageException("Cluster is not configured!"); } @@ -437,6 +451,8 @@ public class LettuceConnectionFactory @Override public LettuceReactiveRedisConnection getReactiveConnection() { + assertInitialized(); + if (isClusterAware()) { return getReactiveClusterConnection(); } @@ -453,6 +469,8 @@ public class LettuceConnectionFactory @Override public LettuceReactiveRedisClusterConnection getReactiveClusterConnection() { + assertInitialized(); + if (!isClusterAware()) { throw new InvalidDataAccessApiUsageException("Cluster is not configured!"); } @@ -481,6 +499,8 @@ public class LettuceConnectionFactory */ public void resetConnection() { + assertInitialized(); + Optionals.toStream(Optional.ofNullable(connection), Optional.ofNullable(reactiveConnection)) .forEach(SharedConnection::resetConnection); @@ -496,6 +516,8 @@ public class LettuceConnectionFactory */ public void validateConnection() { + assertInitialized(); + getOrCreateSharedConnection().validateConnection(); getOrCreateSharedReactiveConnection().validateConnection(); } @@ -801,6 +823,7 @@ public class LettuceConnectionFactory */ @Nullable public AbstractRedisClient getNativeClient() { + assertInitialized(); return this.client; } @@ -1167,6 +1190,11 @@ public class LettuceConnectionFactory return redisUri; } + private void assertInitialized() { + Assert.state(this.initialized, "LettuceConnectionFactory was not initialized through afterPropertiesSet()"); + Assert.state(!this.destroyed, "LettuceConnectionFactory was destroyed and cannot be used anymore"); + } + private static void applyToAll(RedisURI source, Consumer action) { action.accept(source); @@ -1214,6 +1242,9 @@ public class LettuceConnectionFactory @Override public RedisSentinelConnection getSentinelConnection() { + + assertInitialized(); + return new LettuceSentinelConnection(connectionProvider); } diff --git a/src/test/java/org/springframework/data/redis/connection/jedis/JedisConnectionFactorySentinelIntegrationTests.java b/src/test/java/org/springframework/data/redis/connection/jedis/JedisConnectionFactorySentinelIntegrationTests.java index eddbd8464..da4e7fc17 100644 --- a/src/test/java/org/springframework/data/redis/connection/jedis/JedisConnectionFactorySentinelIntegrationTests.java +++ b/src/test/java/org/springframework/data/redis/connection/jedis/JedisConnectionFactorySentinelIntegrationTests.java @@ -90,6 +90,7 @@ class JedisConnectionFactorySentinelIntegrationTests { .sentinel("127.0.0.1", 1).sentinel("127.0.0.1", 26379); factory = new JedisConnectionFactory(oneDownSentinelConfig); + factory.afterPropertiesSet(); assertThat(factory.getSentinelConnection().isOpen()).isTrue(); } } diff --git a/src/test/java/org/springframework/data/redis/connection/jedis/JedisConnectionFactoryUnitTests.java b/src/test/java/org/springframework/data/redis/connection/jedis/JedisConnectionFactoryUnitTests.java index ae795fd84..3d5ec4f4e 100644 --- a/src/test/java/org/springframework/data/redis/connection/jedis/JedisConnectionFactoryUnitTests.java +++ b/src/test/java/org/springframework/data/redis/connection/jedis/JedisConnectionFactoryUnitTests.java @@ -346,6 +346,16 @@ class JedisConnectionFactoryUnitTests { assertThatIllegalStateException().isThrownBy(() -> connectionFactory.setClientName("foo")); } + @Test // GH-2057 + void getConnectionShouldFailIfNotInitialized() { + + JedisConnectionFactory connectionFactory = new JedisConnectionFactory(); + + assertThatIllegalStateException().isThrownBy(connectionFactory::getConnection); + assertThatIllegalStateException().isThrownBy(connectionFactory::getClusterConnection); + assertThatIllegalStateException().isThrownBy(connectionFactory::getSentinelConnection); + } + private JedisConnectionFactory initSpyedConnectionFactory(RedisSentinelConfiguration sentinelConfig, JedisPoolConfig poolConfig) { diff --git a/src/test/java/org/springframework/data/redis/connection/lettuce/LettuceConnectionFactoryUnitTests.java b/src/test/java/org/springframework/data/redis/connection/lettuce/LettuceConnectionFactoryUnitTests.java index fef616f89..3a36f849d 100644 --- a/src/test/java/org/springframework/data/redis/connection/lettuce/LettuceConnectionFactoryUnitTests.java +++ b/src/test/java/org/springframework/data/redis/connection/lettuce/LettuceConnectionFactoryUnitTests.java @@ -1011,7 +1011,19 @@ class LettuceConnectionFactoryUnitTests { LettuceConnectionFactory connectionFactory = new LettuceConnectionFactory(); assertThatIllegalStateException().isThrownBy(connectionFactory::getRequiredNativeClient) - .withMessageContaining("Client not yet initialized"); + .withMessageContaining("was not initialized through"); + } + + @Test // GH-2057 + void getConnectionShouldFailIfNotInitialized() { + + LettuceConnectionFactory connectionFactory = new LettuceConnectionFactory(); + + assertThatIllegalStateException().isThrownBy(connectionFactory::getConnection); + assertThatIllegalStateException().isThrownBy(connectionFactory::getClusterConnection); + assertThatIllegalStateException().isThrownBy(connectionFactory::getSentinelConnection); + assertThatIllegalStateException().isThrownBy(connectionFactory::getReactiveConnection); + assertThatIllegalStateException().isThrownBy(connectionFactory::getReactiveClusterConnection); } @Data