Skip to content

Commit 8641ab1

Browse files
committed
Guard non-initialized RedisConnectionFactory.getConnection() with IllegalStateException.
Obtaining a Connection from RedisConnectionFactory and its reactive variant is now guarded by IllegalStateException that is thrown if the connection factory was not yet initialized. Previously, connections could be obtained where configuration was partially applied. Closes #2057
1 parent 899eea4 commit 8641ab1

File tree

7 files changed

+86
-3
lines changed

7 files changed

+86
-3
lines changed

Diff for: src/main/java/org/springframework/data/redis/connection/ReactiveRedisConnectionFactory.java

+4-2
Original file line numberDiff line numberDiff line change
@@ -32,13 +32,15 @@ public interface ReactiveRedisConnectionFactory extends PersistenceExceptionTran
3232

3333
/**
3434
* @return a reactive Redis connection.
35-
* @since 2.0.
35+
* @throws IllegalStateException if the connection factory requires initialization and the factory was not yet
36+
* initialized.
3637
*/
3738
ReactiveRedisConnection getReactiveConnection();
3839

3940
/**
4041
* @return a reactive Redis Cluster connection.
41-
* @since 2.0
42+
* @throws IllegalStateException if the connection factory requires initialization and the factory was not yet
43+
* initialized.
4244
*/
4345
ReactiveRedisClusterConnection getReactiveClusterConnection();
4446
}

Diff for: src/main/java/org/springframework/data/redis/connection/RedisConnectionFactory.java

+6
Original file line numberDiff line numberDiff line change
@@ -30,13 +30,17 @@ public interface RedisConnectionFactory extends PersistenceExceptionTranslator {
3030
* Provides a suitable connection for interacting with Redis.
3131
*
3232
* @return connection for interacting with Redis.
33+
* @throws IllegalStateException if the connection factory requires initialization and the factory was not yet
34+
* initialized.
3335
*/
3436
RedisConnection getConnection();
3537

3638
/**
3739
* Provides a suitable connection for interacting with Redis Cluster.
3840
*
3941
* @return
42+
* @throws IllegalStateException if the connection factory requires initialization and the factory was not yet
43+
* initialized.
4044
* @since 1.7
4145
*/
4246
RedisClusterConnection getClusterConnection();
@@ -55,6 +59,8 @@ public interface RedisConnectionFactory extends PersistenceExceptionTranslator {
5559
* Provides a suitable connection for interacting with Redis Sentinel.
5660
*
5761
* @return connection for interacting with Redis Sentinel.
62+
* @throws IllegalStateException if the connection factory requires initialization and the factory was not yet
63+
* initialized.
5864
* @since 1.4
5965
*/
6066
RedisSentinelConnection getSentinelConnection();

Diff for: src/main/java/org/springframework/data/redis/connection/jedis/JedisConnectionFactory.java

+21
Original file line numberDiff line numberDiff line change
@@ -73,6 +73,9 @@
7373
* <li>{@link RedisSentinelConfiguration}</li>
7474
* <li>{@link RedisClusterConfiguration}</li>
7575
* </ul>
76+
* <p>
77+
* This connection factory must be {@link #afterPropertiesSet() initialized} prior to {@link #getConnection obtaining
78+
* connections}.
7679
*
7780
* @author Costin Leau
7881
* @author Thomas Darimont
@@ -104,6 +107,9 @@ public class JedisConnectionFactory implements InitializingBean, DisposableBean,
104107
private @Nullable ClusterTopologyProvider topologyProvider;
105108
private @Nullable ClusterCommandExecutor clusterCommandExecutor;
106109

110+
private boolean initialized;
111+
private boolean destroyed;
112+
107113
/**
108114
* Constructs a new <code>JedisConnectionFactory</code> instance with default settings (default connection pooling, no
109115
* shard information).
@@ -350,6 +356,8 @@ public void afterPropertiesSet() {
350356
new JedisClusterConnection.JedisClusterNodeResourceProvider(this.cluster, this.topologyProvider),
351357
EXCEPTION_TRANSLATION);
352358
}
359+
360+
this.initialized = true;
353361
}
354362

355363
private JedisClientConfig createClientConfig(@Nullable String username, RedisPassword password) {
@@ -484,6 +492,8 @@ public void destroy() {
484492
log.warn("Cannot properly close cluster command executor", ex);
485493
}
486494
}
495+
496+
this.destroyed = true;
487497
}
488498

489499
/*
@@ -492,6 +502,8 @@ public void destroy() {
492502
*/
493503
public RedisConnection getConnection() {
494504

505+
assertInitialized();
506+
495507
if (isRedisClusterAware()) {
496508
return getClusterConnection();
497509
}
@@ -517,6 +529,8 @@ public RedisConnection getConnection() {
517529
@Override
518530
public RedisClusterConnection getClusterConnection() {
519531

532+
assertInitialized();
533+
520534
if (!isRedisClusterAware()) {
521535
throw new InvalidDataAccessApiUsageException("Cluster is not configured!");
522536
}
@@ -876,6 +890,8 @@ public boolean isRedisClusterAware() {
876890
@Override
877891
public RedisSentinelConnection getSentinelConnection() {
878892

893+
assertInitialized();
894+
879895
if (!isRedisSentinelAware()) {
880896
throw new InvalidDataAccessResourceUsageException("No Sentinels configured");
881897
}
@@ -945,6 +961,11 @@ private MutableJedisClientConfiguration getMutableConfiguration() {
945961
return (MutableJedisClientConfiguration) clientConfiguration;
946962
}
947963

964+
private void assertInitialized() {
965+
Assert.state(this.initialized, "JedisConnectionFactory was not initialized through afterPropertiesSet()");
966+
Assert.state(!this.destroyed, "JedisConnectionFactory was destroyed and cannot be used anymore");
967+
}
968+
948969
/**
949970
* Mutable implementation of {@link JedisClientConfiguration}.
950971
*

Diff for: src/main/java/org/springframework/data/redis/connection/lettuce/LettuceConnectionFactory.java

+31
Original file line numberDiff line numberDiff line change
@@ -84,6 +84,9 @@
8484
* <li>{@link RedisSentinelConfiguration}</li>
8585
* <li>{@link RedisClusterConfiguration}</li>
8686
* </ul>
87+
* <p>
88+
* This connection factory must be {@link #afterPropertiesSet() initialized} prior to {@link #getConnection obtaining
89+
* connections}.
8790
*
8891
* @author Costin Leau
8992
* @author Jennifer Hickey
@@ -124,6 +127,9 @@ public class LettuceConnectionFactory
124127

125128
private @Nullable ClusterCommandExecutor clusterCommandExecutor;
126129

130+
private boolean initialized;
131+
private boolean destroyed;
132+
127133
/**
128134
* Constructs a new {@link LettuceConnectionFactory} instance with default settings.
129135
*/
@@ -293,6 +299,8 @@ public void afterPropertiesSet() {
293299
EXCEPTION_TRANSLATION);
294300
}
295301

302+
this.initialized = true;
303+
296304
if (getEagerInitialization() && getShareNativeConnection()) {
297305
initConnection();
298306
}
@@ -329,6 +337,8 @@ public void destroy() {
329337
log.warn("Cannot properly close cluster command executor", ex);
330338
}
331339
}
340+
341+
this.destroyed = true;
332342
}
333343

334344
private void dispose(LettuceConnectionProvider connectionProvider) {
@@ -351,6 +361,8 @@ private void dispose(LettuceConnectionProvider connectionProvider) {
351361
*/
352362
public RedisConnection getConnection() {
353363

364+
assertInitialized();
365+
354366
if (isClusterAware()) {
355367
return getClusterConnection();
356368
}
@@ -368,6 +380,8 @@ public RedisConnection getConnection() {
368380
@Override
369381
public RedisClusterConnection getClusterConnection() {
370382

383+
assertInitialized();
384+
371385
if (!isClusterAware()) {
372386
throw new InvalidDataAccessApiUsageException("Cluster is not configured!");
373387
}
@@ -437,6 +451,8 @@ protected LettuceClusterConnection doCreateLettuceClusterConnection(
437451
@Override
438452
public LettuceReactiveRedisConnection getReactiveConnection() {
439453

454+
assertInitialized();
455+
440456
if (isClusterAware()) {
441457
return getReactiveClusterConnection();
442458
}
@@ -453,6 +469,8 @@ public LettuceReactiveRedisConnection getReactiveConnection() {
453469
@Override
454470
public LettuceReactiveRedisClusterConnection getReactiveClusterConnection() {
455471

472+
assertInitialized();
473+
456474
if (!isClusterAware()) {
457475
throw new InvalidDataAccessApiUsageException("Cluster is not configured!");
458476
}
@@ -481,6 +499,8 @@ public void initConnection() {
481499
*/
482500
public void resetConnection() {
483501

502+
assertInitialized();
503+
484504
Optionals.toStream(Optional.ofNullable(connection), Optional.ofNullable(reactiveConnection))
485505
.forEach(SharedConnection::resetConnection);
486506

@@ -496,6 +516,8 @@ public void resetConnection() {
496516
*/
497517
public void validateConnection() {
498518

519+
assertInitialized();
520+
499521
getOrCreateSharedConnection().validateConnection();
500522
getOrCreateSharedReactiveConnection().validateConnection();
501523
}
@@ -801,6 +823,7 @@ public void setClientName(@Nullable String clientName) {
801823
*/
802824
@Nullable
803825
public AbstractRedisClient getNativeClient() {
826+
assertInitialized();
804827
return this.client;
805828
}
806829

@@ -1167,6 +1190,11 @@ private RedisURI getSentinelRedisURI() {
11671190
return redisUri;
11681191
}
11691192

1193+
private void assertInitialized() {
1194+
Assert.state(this.initialized, "LettuceConnectionFactory was not initialized through afterPropertiesSet()");
1195+
Assert.state(!this.destroyed, "LettuceConnectionFactory was destroyed and cannot be used anymore");
1196+
}
1197+
11701198
private static void applyToAll(RedisURI source, Consumer<RedisURI> action) {
11711199

11721200
action.accept(source);
@@ -1214,6 +1242,9 @@ private void applyAuthentication(RedisURI.Builder builder) {
12141242

12151243
@Override
12161244
public RedisSentinelConnection getSentinelConnection() {
1245+
1246+
assertInitialized();
1247+
12171248
return new LettuceSentinelConnection(connectionProvider);
12181249
}
12191250

Diff for: src/test/java/org/springframework/data/redis/connection/jedis/JedisConnectionFactorySentinelIntegrationTests.java

+1
Original file line numberDiff line numberDiff line change
@@ -90,6 +90,7 @@ void shouldNotFailOnFirstSentinelDown() {
9090
.sentinel("127.0.0.1", 1).sentinel("127.0.0.1", 26379);
9191

9292
factory = new JedisConnectionFactory(oneDownSentinelConfig);
93+
factory.afterPropertiesSet();
9394
assertThat(factory.getSentinelConnection().isOpen()).isTrue();
9495
}
9596
}

Diff for: src/test/java/org/springframework/data/redis/connection/jedis/JedisConnectionFactoryUnitTests.java

+10
Original file line numberDiff line numberDiff line change
@@ -346,6 +346,16 @@ void shouldDenyChangesToImmutableClientConfiguration() throws NoSuchAlgorithmExc
346346
assertThatIllegalStateException().isThrownBy(() -> connectionFactory.setClientName("foo"));
347347
}
348348

349+
@Test // GH-2057
350+
void getConnectionShouldFailIfNotInitialized() {
351+
352+
JedisConnectionFactory connectionFactory = new JedisConnectionFactory();
353+
354+
assertThatIllegalStateException().isThrownBy(connectionFactory::getConnection);
355+
assertThatIllegalStateException().isThrownBy(connectionFactory::getClusterConnection);
356+
assertThatIllegalStateException().isThrownBy(connectionFactory::getSentinelConnection);
357+
}
358+
349359
private JedisConnectionFactory initSpyedConnectionFactory(RedisSentinelConfiguration sentinelConfig,
350360
JedisPoolConfig poolConfig) {
351361

Diff for: src/test/java/org/springframework/data/redis/connection/lettuce/LettuceConnectionFactoryUnitTests.java

+13-1
Original file line numberDiff line numberDiff line change
@@ -1011,7 +1011,19 @@ void getNativeClientShouldFailIfNotInitialized() {
10111011
LettuceConnectionFactory connectionFactory = new LettuceConnectionFactory();
10121012

10131013
assertThatIllegalStateException().isThrownBy(connectionFactory::getRequiredNativeClient)
1014-
.withMessageContaining("Client not yet initialized");
1014+
.withMessageContaining("was not initialized through");
1015+
}
1016+
1017+
@Test // GH-2057
1018+
void getConnectionShouldFailIfNotInitialized() {
1019+
1020+
LettuceConnectionFactory connectionFactory = new LettuceConnectionFactory();
1021+
1022+
assertThatIllegalStateException().isThrownBy(connectionFactory::getConnection);
1023+
assertThatIllegalStateException().isThrownBy(connectionFactory::getClusterConnection);
1024+
assertThatIllegalStateException().isThrownBy(connectionFactory::getSentinelConnection);
1025+
assertThatIllegalStateException().isThrownBy(connectionFactory::getReactiveConnection);
1026+
assertThatIllegalStateException().isThrownBy(connectionFactory::getReactiveClusterConnection);
10151027
}
10161028

10171029
@Data

0 commit comments

Comments
 (0)