diff --git a/src/main/java/org/springframework/data/redis/connection/lettuce/ClusterConnectionProvider.java b/src/main/java/org/springframework/data/redis/connection/lettuce/ClusterConnectionProvider.java index ae0507f3b..b7dd809df 100644 --- a/src/main/java/org/springframework/data/redis/connection/lettuce/ClusterConnectionProvider.java +++ b/src/main/java/org/springframework/data/redis/connection/lettuce/ClusterConnectionProvider.java @@ -25,6 +25,7 @@ import io.lettuce.core.pubsub.StatefulRedisPubSubConnection; * Connection provider for Cluster connections. * * @author Mark Paluch + * @author Christoph Strobl * @since 2.0 */ class ClusterConnectionProvider implements LettuceConnectionProvider { @@ -42,17 +43,16 @@ class ClusterConnectionProvider implements LettuceConnectionProvider { * (non-Javadoc) * @see org.springframework.data.redis.connection.lettuce.LettuceConnectionProvider#getConnection(java.lang.Class) */ - @SuppressWarnings("rawtypes") @Override - public StatefulConnection getConnection(Class connectionType) { + public > T getConnection(Class connectionType) { if (connectionType.equals(StatefulRedisPubSubConnection.class)) { - return client.connectPubSub(codec); + return connectionType.cast(client.connectPubSub(codec)); } if (StatefulRedisClusterConnection.class.isAssignableFrom(connectionType) || connectionType.equals(StatefulConnection.class)) { - return client.connect(codec); + return connectionType.cast(client.connect(codec)); } throw new UnsupportedOperationException("Connection type " + connectionType + " not supported!"); diff --git a/src/main/java/org/springframework/data/redis/connection/lettuce/DefaultLettuceClientConfiguration.java b/src/main/java/org/springframework/data/redis/connection/lettuce/DefaultLettuceClientConfiguration.java index 3745fa341..91d705c0a 100644 --- a/src/main/java/org/springframework/data/redis/connection/lettuce/DefaultLettuceClientConfiguration.java +++ b/src/main/java/org/springframework/data/redis/connection/lettuce/DefaultLettuceClientConfiguration.java @@ -25,6 +25,7 @@ import java.util.Optional; * Default implementation of {@literal LettuceClientConfiguration}. * * @author Mark Paluch + * @author Christoph Strobl * @since 2.0 */ class DefaultLettuceClientConfiguration implements LettuceClientConfiguration { @@ -57,14 +58,6 @@ class DefaultLettuceClientConfiguration implements LettuceClientConfiguration { return useSsl; } - /* (non-Javadoc) - * @see org.springframework.data.redis.connection.lettuce.LettuceClientConfiguration#isUsePooling() - */ - @Override - public boolean isUsePooling() { - return false; - } - /* (non-Javadoc) * @see org.springframework.data.redis.connection.lettuce.LettuceClientConfiguration#isVerifyPeer() */ diff --git a/src/main/java/org/springframework/data/redis/connection/lettuce/DefaultLettucePoolingClientConfiguration.java b/src/main/java/org/springframework/data/redis/connection/lettuce/DefaultLettucePoolingClientConfiguration.java index eef977d71..6f6235ea3 100644 --- a/src/main/java/org/springframework/data/redis/connection/lettuce/DefaultLettucePoolingClientConfiguration.java +++ b/src/main/java/org/springframework/data/redis/connection/lettuce/DefaultLettucePoolingClientConfiguration.java @@ -19,6 +19,7 @@ import io.lettuce.core.ClientOptions; import io.lettuce.core.resource.ClientResources; import java.time.Duration; +import java.util.Optional; import org.apache.commons.pool2.impl.GenericObjectPoolConfig; @@ -26,33 +27,87 @@ import org.apache.commons.pool2.impl.GenericObjectPoolConfig; * Default implementation of {@literal LettucePoolingClientConfiguration}. * * @author Mark Paluch + * @author Christoph Strobl * @since 2.0 */ -class DefaultLettucePoolingClientConfiguration extends DefaultLettuceClientConfiguration - implements LettucePoolingClientConfiguration { +class DefaultLettucePoolingClientConfiguration implements LettucePoolingClientConfiguration { + private final LettuceClientConfiguration clientConfiguration; private final GenericObjectPoolConfig poolConfig; - DefaultLettucePoolingClientConfiguration(boolean useSsl, boolean verifyPeer, boolean startTls, - ClientResources clientResources, ClientOptions clientOptions, Duration timeout, Duration shutdownTimeout, + DefaultLettucePoolingClientConfiguration(LettuceClientConfiguration clientConfiguration, GenericObjectPoolConfig poolConfig) { - super(useSsl, verifyPeer, startTls, clientResources, clientOptions, timeout, shutdownTimeout); - + this.clientConfiguration = clientConfiguration; this.poolConfig = poolConfig; } - /* (non-Javadoc) - * @see org.springframework.data.redis.connection.lettuce.LettuceClientConfiguration#isUsePooling() - */ - @Override - public boolean isUsePooling() { - return true; - } - /* * (non-Javadoc) - * @see org.springframework.data.redis.connection.lettuce.LettucePoolingClientConfiguration#getPoolConfig() + * @see org.springframework.data.redis.connection.lettuce.LettuceClientConfiguration#isUseSsl() + */ + @Override + public boolean isUseSsl() { + return clientConfiguration.isUseSsl(); + } + + /* + * (non-Javadoc) + * @see org.springframework.data.redis.connection.lettuce.LettuceClientConfiguration#isVerifyPeer() + */ + @Override + public boolean isVerifyPeer() { + return clientConfiguration.isVerifyPeer(); + } + + /* + * (non-Javadoc) + * @see org.springframework.data.redis.connection.lettuce.LettuceClientConfiguration#isStartTls() + */ + @Override + public boolean isStartTls() { + return clientConfiguration.isStartTls(); + } + + /* + * (non-Javadoc) + * @see org.springframework.data.redis.connection.lettuce.LettuceClientConfiguration#getClientResources() + */ + @Override + public Optional getClientResources() { + return clientConfiguration.getClientResources(); + } + + /* + * (non-Javadoc) + * @see org.springframework.data.redis.connection.lettuce.LettuceClientConfiguration#getClientOptions() + */ + @Override + public Optional getClientOptions() { + return clientConfiguration.getClientOptions(); + } + + /* + * (non-Javadoc) + * @see org.springframework.data.redis.connection.lettuce.LettuceClientConfiguration#getCommandTimeout() + */ + @Override + public Duration getCommandTimeout() { + return clientConfiguration.getCommandTimeout(); + } + + /* + * (non-Javadoc) + * @see org.springframework.data.redis.connection.lettuce.LettuceClientConfiguration#getShutdownTimeout() + */ + @Override + public Duration getShutdownTimeout() { + return clientConfiguration.getShutdownTimeout(); + } + + /* + * (non-Javadoc) + * @see org.springframework.data.redis.connection.lettuce.LettuceClientConfiguration.LettucePoolingClientConfiguration#getPoolConfig() */ @Override public GenericObjectPoolConfig getPoolConfig() { diff --git a/src/main/java/org/springframework/data/redis/connection/lettuce/LettuceClientConfiguration.java b/src/main/java/org/springframework/data/redis/connection/lettuce/LettuceClientConfiguration.java index 48238b02c..b3f556bd0 100644 --- a/src/main/java/org/springframework/data/redis/connection/lettuce/LettuceClientConfiguration.java +++ b/src/main/java/org/springframework/data/redis/connection/lettuce/LettuceClientConfiguration.java @@ -54,11 +54,6 @@ public interface LettuceClientConfiguration { */ boolean isUseSsl(); - /** - * @return {@literal true} to use connection-pooling. - */ - boolean isUsePooling(); - /** * @return {@literal true} to verify peers when using {@link #isUseSsl() SSL}. */ @@ -97,7 +92,7 @@ public interface LettuceClientConfiguration { * @return a new {@link LettuceClientConfigurationBuilder} to build {@link LettuceClientConfiguration}. */ static LettuceClientConfigurationBuilder builder() { - return new DefaultLettuceClientConfigurationBuilder(); + return new LettuceClientConfigurationBuilder(); } /** @@ -126,101 +121,10 @@ public interface LettuceClientConfiguration { } /** - * Builder for {@link LettuceClientConfiguration}. + * @author Mark Paluch + * @author Christoph Strobl */ - interface LettuceClientConfigurationBuilder { - - /** - * Enable SSL connections. - * - * @return {@link LettuceSslClientConfigurationBuilder}. - */ - LettuceSslClientConfigurationBuilder useSsl(); - - /** - * Configure {@link ClientResources}. - * - * @param clientResources must not be {@literal null}. - * @return {@literal this} builder. - * @throws IllegalArgumentException if clientResources is {@literal null}. - */ - LettuceClientConfigurationBuilder clientResources(ClientResources clientResources); - - /** - * Configure {@link ClientOptions}. - * - * @param clientOptions must not be {@literal null}. - * @return {@literal this} builder. - * @throws IllegalArgumentException if clientOptions is {@literal null}. - */ - LettuceClientConfigurationBuilder clientOptions(ClientOptions clientOptions); - - /** - * Configure a command timeout. - * - * @param timeout must not be {@literal null}. - * @return {@literal this} builder. - * @throws IllegalArgumentException if timeout is {@literal null}. - */ - LettuceClientConfigurationBuilder commandTimeout(Duration timeout); - - /** - * Configure a shutdown timeout. - * - * @param shutdownTimeout must not be {@literal null}. - * @return {@literal this} builder. - * @throws IllegalArgumentException if shutdownTimeout is {@literal null}. - */ - LettuceClientConfigurationBuilder shutdownTimeout(Duration shutdownTimeout); - - /** - * Build the {@link LettuceClientConfiguration} with the configuration applied from this builder. - * - * @return a new {@link LettuceClientConfiguration} object. - */ - LettuceClientConfiguration build(); - } - - /** - * Builder for SSL-related {@link LettuceClientConfiguration}. - */ - interface LettuceSslClientConfigurationBuilder { - - /** - * Disable peer verification. - * - * @return {@literal this} builder. - */ - LettuceSslClientConfigurationBuilder disablePeerVerification(); - - /** - * Enable Start TLS to send the first bytes unencrypted. - * - * @return {@literal this} builder. - */ - LettuceSslClientConfigurationBuilder startTls(); - - /** - * Return to {@link LettuceClientConfigurationBuilder}. - * - * @return {@link LettuceClientConfigurationBuilder}. - */ - LettuceClientConfigurationBuilder and(); - - /** - * Build the {@link LettuceClientConfiguration} with the configuration applied from this builder. - * - * @return a new {@link LettuceClientConfiguration} object. - */ - LettuceClientConfiguration build(); - } - - /** - * Default {@link LettuceClientConfigurationBuilder} implementation to build an immutable - * {@link LettuceClientConfiguration}. - */ - class DefaultLettuceClientConfigurationBuilder - implements LettuceClientConfigurationBuilder, LettuceSslClientConfigurationBuilder { + class LettuceClientConfigurationBuilder { boolean useSsl; boolean verifyPeer = true; @@ -230,55 +134,26 @@ public interface LettuceClientConfiguration { Duration timeout = Duration.ofSeconds(RedisURI.DEFAULT_TIMEOUT); Duration shutdownTimeout = Duration.ofMillis(100); - DefaultLettuceClientConfigurationBuilder() {} + LettuceClientConfigurationBuilder() {} - /* - * (non-Javadoc) - * @see org.springframework.data.redis.connection.lettuce.LettuceClientConfiguration.LettuceClientConfigurationBuilder#useSsl() + /** + * Enable SSL connections. + * + * @return {@link LettuceSslClientConfigurationBuilder}. */ - @Override public LettuceSslClientConfigurationBuilder useSsl() { this.useSsl = true; - return this; + return new LettuceSslClientConfigurationBuilder(this); } - /* - * (non-Javadoc) - * @see org.springframework.data.redis.connection.lettuce.LettuceClientConfiguration.LettuceSslClientConfigurationBuilder#disablePeerVerification() + /** + * Configure {@link ClientResources}. + * + * @param clientResources must not be {@literal null}. + * @return {@literal this} builder. + * @throws IllegalArgumentException if clientResources is {@literal null}. */ - @Override - public LettuceSslClientConfigurationBuilder disablePeerVerification() { - - this.verifyPeer = false; - return this; - } - - /* - * (non-Javadoc) - * @see org.springframework.data.redis.connection.lettuce.LettuceClientConfiguration.LettuceSslClientConfigurationBuilder#startTls() - */ - @Override - public LettuceSslClientConfigurationBuilder startTls() { - - this.startTls = true; - return this; - } - - /* - * (non-Javadoc) - * @see org.springframework.data.redis.connection.lettuce.LettuceClientConfiguration.LettuceSslClientConfigurationBuilder#and() - */ - @Override - public LettuceClientConfigurationBuilder and() { - return this; - } - - /* - * (non-Javadoc) - * @see org.springframework.data.redis.connection.lettuce.LettuceClientConfiguration.LettuceClientConfigurationBuilder#clientResources(io.lettuce.core.resource.ClientResources) - */ - @Override public LettuceClientConfigurationBuilder clientResources(ClientResources clientResources) { Assert.notNull(clientResources, "ClientResources must not be null!"); @@ -287,11 +162,13 @@ public interface LettuceClientConfiguration { return this; } - /* - * (non-Javadoc) - * @see org.springframework.data.redis.connection.lettuce.LettuceClientConfiguration.LettuceClientConfigurationBuilder#clientOptions(io.lettuce.core.ClientOptions) + /** + * Configure {@link ClientOptions}. + * + * @param clientOptions must not be {@literal null}. + * @return {@literal this} builder. + * @throws IllegalArgumentException if clientOptions is {@literal null}. */ - @Override public LettuceClientConfigurationBuilder clientOptions(ClientOptions clientOptions) { Assert.notNull(clientOptions, "ClientOptions must not be null!"); @@ -300,11 +177,13 @@ public interface LettuceClientConfiguration { return this; } - /* - * (non-Javadoc) - * @see org.springframework.data.redis.connection.lettuce.LettuceClientConfiguration.LettuceClientConfigurationBuilder#timeout(java.time.Duration) + /** + * Configure a command timeout. + * + * @param timeout must not be {@literal null}. + * @return {@literal this} builder. + * @throws IllegalArgumentException if timeout is {@literal null}. */ - @Override public LettuceClientConfigurationBuilder commandTimeout(Duration timeout) { Assert.notNull(timeout, "Duration must not be null!"); @@ -313,11 +192,13 @@ public interface LettuceClientConfiguration { return this; } - /* - * (non-Javadoc) - * @see org.springframework.data.redis.connection.lettuce.LettuceClientConfiguration.LettuceClientConfigurationBuilder#shutdownTimeout(java.time.Duration) + /** + * Configure a shutdown timeout. + * + * @param shutdownTimeout must not be {@literal null}. + * @return {@literal this} builder. + * @throws IllegalArgumentException if shutdownTimeout is {@literal null}. */ - @Override public LettuceClientConfigurationBuilder shutdownTimeout(Duration shutdownTimeout) { Assert.notNull(timeout, "Duration must not be null!"); @@ -326,14 +207,69 @@ public interface LettuceClientConfiguration { return this; } - /* - * (non-Javadoc) - * @see org.springframework.data.redis.connection.lettuce.LettuceClientConfiguration.LettuceClientConfigurationBuilder#build() + /** + * Build the {@link LettuceClientConfiguration} with the configuration applied from this builder. + * + * @return a new {@link LettuceClientConfiguration} object. */ - @Override public LettuceClientConfiguration build() { + return new DefaultLettuceClientConfiguration(useSsl, verifyPeer, startTls, clientResources, clientOptions, timeout, shutdownTimeout); } } + + /** + * Builder for SSL-related {@link LettuceClientConfiguration}. + */ + class LettuceSslClientConfigurationBuilder { + + private LettuceClientConfigurationBuilder delegate; + + LettuceSslClientConfigurationBuilder(LettuceClientConfigurationBuilder delegate) { + + Assert.notNull(delegate, "Delegate client configuration builder must not be null!"); + this.delegate = delegate; + } + + /** + * Disable peer verification. + * + * @return {@literal this} builder. + */ + LettuceSslClientConfigurationBuilder disablePeerVerification() { + + delegate.verifyPeer = false; + return this; + } + + /** + * Enable Start TLS to send the first bytes unencrypted. + * + * @return {@literal this} builder. + */ + LettuceSslClientConfigurationBuilder startTls() { + + delegate.startTls = true; + return this; + } + + /** + * Return to {@link LettuceClientConfigurationBuilder}. + * + * @return {@link LettuceClientConfigurationBuilder}. + */ + LettuceClientConfigurationBuilder and() { + return delegate; + } + + /** + * Build the {@link LettuceClientConfiguration} with the configuration applied from this builder. + * + * @return a new {@link LettuceClientConfiguration} object. + */ + LettuceClientConfiguration build() { + return delegate.build(); + } + } } diff --git a/src/main/java/org/springframework/data/redis/connection/lettuce/LettuceClusterConnection.java b/src/main/java/org/springframework/data/redis/connection/lettuce/LettuceClusterConnection.java index 757f97a90..d93f398c2 100644 --- a/src/main/java/org/springframework/data/redis/connection/lettuce/LettuceClusterConnection.java +++ b/src/main/java/org/springframework/data/redis/connection/lettuce/LettuceClusterConnection.java @@ -619,7 +619,7 @@ public class LettuceClusterConnection extends LettuceConnection implements Defau if (connection == null) { synchronized (this) { if (connection == null) { - this.connection = connectionProvider.getConnection(); + this.connection = connectionProvider.getConnection(StatefulRedisClusterConnection.class); } } } diff --git a/src/main/java/org/springframework/data/redis/connection/lettuce/LettuceConnection.java b/src/main/java/org/springframework/data/redis/connection/lettuce/LettuceConnection.java index d6c3727c6..f50ce9fa7 100644 --- a/src/main/java/org/springframework/data/redis/connection/lettuce/LettuceConnection.java +++ b/src/main/java/org/springframework/data/redis/connection/lettuce/LettuceConnection.java @@ -820,7 +820,7 @@ public class LettuceConnection extends AbstractRedisConnection { protected StatefulRedisPubSubConnection switchToPubSub() { close(); - return (StatefulRedisPubSubConnection) connectionProvider.getConnection(StatefulRedisPubSubConnection.class); + return connectionProvider.getConnection(StatefulRedisPubSubConnection.class); } void pipeline(LettuceResult result) { @@ -910,7 +910,7 @@ public class LettuceConnection extends AbstractRedisConnection { } protected StatefulConnection doGetAsyncDedicatedConnection() { - return connectionProvider.getConnection(); + return connectionProvider.getConnection(StatefulConnection.class); } io.lettuce.core.ScanCursor getScanCursor(long cursorId) { @@ -1206,9 +1206,8 @@ public class LettuceConnection extends AbstractRedisConnection { private final LettucePool pool; @Override - @SuppressWarnings("unchecked") - public StatefulConnection getConnection(Class connectionType) { - return pool.getResource(); + public > T getConnection(Class connectionType) { + return connectionType.cast(pool.getResource()); } @Override 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 243ad4536..3ecb738e8 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 @@ -768,7 +768,7 @@ public class LettuceConnectionFactory StatefulRedisConnection connection; if (!isClusterAware()) { - connection = connectionProvider.getConnection(); + connection = connectionProvider.getConnection(StatefulRedisConnection.class); if (getDatabase() > 0) { connection.sync().select(getDatabase()); } @@ -785,8 +785,9 @@ public class LettuceConnectionFactory LettuceConnectionProvider connectionProvider = doConnectionProvider(client, codec); - if (this.clientConfiguration.isUsePooling()) { - return new LettucePoolingConnectionProvider(connectionProvider, this.clientConfiguration); + if (this.clientConfiguration instanceof LettucePoolingClientConfiguration) { + return new LettucePoolingConnectionProvider(connectionProvider, + (LettucePoolingClientConfiguration) this.clientConfiguration); } return connectionProvider; @@ -904,14 +905,6 @@ public class LettuceConnectionFactory return useSsl; } - /* (non-Javadoc) - * @see org.springframework.data.redis.connection.lettuce.LettuceClientConfiguration#isUsePooling() - */ - @Override - public boolean isUsePooling() { - return false; - } - public void setUseSsl(boolean useSsl) { this.useSsl = useSsl; } diff --git a/src/main/java/org/springframework/data/redis/connection/lettuce/LettuceConnectionProvider.java b/src/main/java/org/springframework/data/redis/connection/lettuce/LettuceConnectionProvider.java index e81ce1d21..afe74f986 100644 --- a/src/main/java/org/springframework/data/redis/connection/lettuce/LettuceConnectionProvider.java +++ b/src/main/java/org/springframework/data/redis/connection/lettuce/LettuceConnectionProvider.java @@ -31,6 +31,7 @@ import io.lettuce.core.api.StatefulConnection; * with an appropriate codec. * * @author Mark Paluch + * @author Christoph Strobl * @since 2.0 * @see StatefulConnection */ @@ -46,18 +47,7 @@ public interface LettuceConnectionProvider { * longer in use. */ @SuppressWarnings("rawtypes") - StatefulConnection getConnection(Class connectionType); - - /** - * Request a connection. - * - * @return the requested connection. Must be {@link #release(StatefulConnection) released} if the connection is no - * longer in use. - */ - @SuppressWarnings("unchecked") - default T getConnection() { - return (T) getConnection(StatefulConnection.class); - } + > T getConnection(Class connectionType); /** * Release the {@link StatefulConnection connection}. Closes connection {@link StatefulConnection#close()} by default. @@ -83,6 +73,6 @@ public interface LettuceConnectionProvider { * @return the requested connection. */ @SuppressWarnings("rawtypes") - StatefulConnection getConnection(Class connectionType, RedisURI redisURI); + > T getConnection(Class connectionType, RedisURI redisURI); } } diff --git a/src/main/java/org/springframework/data/redis/connection/lettuce/LettucePoolingClientConfiguration.java b/src/main/java/org/springframework/data/redis/connection/lettuce/LettucePoolingClientConfiguration.java index 4e4be1e32..56d2093d8 100644 --- a/src/main/java/org/springframework/data/redis/connection/lettuce/LettucePoolingClientConfiguration.java +++ b/src/main/java/org/springframework/data/redis/connection/lettuce/LettucePoolingClientConfiguration.java @@ -15,32 +15,44 @@ */ package org.springframework.data.redis.connection.lettuce; +import io.lettuce.core.ClientOptions; +import io.lettuce.core.resource.ClientResources; + +import java.time.Duration; + import org.apache.commons.pool2.impl.GenericObjectPoolConfig; -import org.springframework.data.redis.connection.jedis.JedisClientConfiguration; import org.springframework.util.Assert; /** + * Redis client configuration for lettuce using a driver level pooled connection by adding pooling specific + * configuration to {@link LettuceClientConfiguration}. + * * @author Mark Paluch + * @author Christoph Strobl + * @since 2.0 */ public interface LettucePoolingClientConfiguration extends LettuceClientConfiguration { + /** + * @return the {@link GenericObjectPoolConfig}. Never {@literal null}. + */ + GenericObjectPoolConfig getPoolConfig(); + /** * Creates a new {@link LettucePoolingClientConfigurationBuilder} to build {@link LettucePoolingClientConfiguration} - * to be used with the jedis client. + * to be used with the Lettuce client. * * @return a new {@link LettucePoolingClientConfigurationBuilder} to build {@link LettucePoolingClientConfiguration}. */ static LettucePoolingClientConfigurationBuilder builder() { - return new DefaultLettucePoolingClientConfigurationBuilder(); + return new LettucePoolingClientConfigurationBuilder(); } /** - * Creates a default {@link LettucePoolingClientConfiguration} with: + * Creates a default {@link LettucePoolingClientConfiguration} with *
*
SSL
*
no
- *
Pooling
- *
yes
*
Peer Verification
*
yes
*
Start TLS
@@ -53,6 +65,8 @@ public interface LettucePoolingClientConfiguration extends LettuceClientConfigur *
60 Seconds
*
Shutdown Timeout
*
2 Seconds
+ *
pool config
+ *
default {@link GenericObjectPoolConfig}
*
* * @return a {@link LettucePoolingClientConfiguration} with defaults. @@ -62,50 +76,80 @@ public interface LettucePoolingClientConfiguration extends LettuceClientConfigur } /** - * @return the optional {@link GenericObjectPoolConfig}. + * @author Mark Paluch + * @author Christoph Strobl */ - GenericObjectPoolConfig getPoolConfig(); - - /** - * Builder for Pooling-related {@link LettuceClientConfiguration}. - */ - interface LettucePoolingClientConfigurationBuilder { - - /** - * @param poolConfig must not be {@literal null}. - * @return {@literal this} builder. - * @throws IllegalArgumentException if poolConfig is {@literal null}. - */ - LettucePoolingClientConfigurationBuilder poolConfig(GenericObjectPoolConfig poolConfig); - - /** - * Return to {@link LettuceClientConfigurationBuilder}. - * - * @return {@link LettuceClientConfigurationBuilder}. - */ - LettuceClientConfigurationBuilder and(); - - /** - * Build the {@link JedisClientConfiguration} with the configuration applied from this builder. - * - * @return a new {@link JedisClientConfiguration} object. - */ - LettucePoolingClientConfiguration build(); - } - - /** - * Default {@link LettuceClientConfigurationBuilder} implementation to build an immutable - * {@link LettuceClientConfiguration}. - */ - class DefaultLettucePoolingClientConfigurationBuilder extends DefaultLettuceClientConfigurationBuilder - implements LettucePoolingClientConfigurationBuilder { + class LettucePoolingClientConfigurationBuilder extends LettuceClientConfigurationBuilder { GenericObjectPoolConfig poolConfig = new GenericObjectPoolConfig(); + LettucePoolingClientConfigurationBuilder() { + super(); + } + + /* + * (non-Javadoc) + * @see org.springframework.data.redis.connection.lettuce.LettuceClientConfiguration.LettuceClientConfigurationBuilder#useSsl() + */ @Override + public LettucePoolingSslClientConfigurationBuilder useSsl() { + + super.useSsl(); + return new LettucePoolingSslClientConfigurationBuilder(this); + } + + /* + * (non-Javadoc) + * @see org.springframework.data.redis.connection.lettuce.LettuceClientConfiguration.LettuceClientConfigurationBuilder#clientResources(io.lettuce.core.resource.ClientResources) + */ + @Override + public LettucePoolingClientConfigurationBuilder clientResources(ClientResources clientResources) { + + super.clientResources(clientResources); + return this; + } + + /* + * (non-Javadoc) + * @see org.springframework.data.redis.connection.lettuce.LettuceClientConfiguration.LettuceClientConfigurationBuilder#clientOptions(io.lettuce.core.ClientOptions) + */ + @Override + public LettucePoolingClientConfigurationBuilder clientOptions(ClientOptions clientOptions) { + + super.clientOptions(clientOptions); + return this; + } + + /* + * (non-Javadoc) + * @see org.springframework.data.redis.connection.lettuce.LettuceClientConfiguration.LettuceClientConfigurationBuilder#commandTimeout(java.time.Duration) + */ + @Override + public LettucePoolingClientConfigurationBuilder commandTimeout(Duration timeout) { + + super.commandTimeout(timeout); + return this; + } + + /* + * (non-Javadoc) + * @see org.springframework.data.redis.connection.lettuce.LettuceClientConfiguration.LettuceClientConfigurationBuilder#shutdownTimeout(java.time.Duration) + */ + @Override + public LettucePoolingClientConfigurationBuilder shutdownTimeout(Duration shutdownTimeout) { + + super.shutdownTimeout(shutdownTimeout); + return this; + } + + /** + * Set the {@link GenericObjectPoolConfig} used by the driver. + * + * @param poolConfig must not be {@literal null}. + */ public LettucePoolingClientConfigurationBuilder poolConfig(GenericObjectPoolConfig poolConfig) { - Assert.notNull(poolConfig, "GenericObjectPoolConfig must not be null!"); + Assert.notNull(poolConfig, "PoolConfig must not be null!"); this.poolConfig = poolConfig; return this; @@ -117,8 +161,57 @@ public interface LettucePoolingClientConfiguration extends LettuceClientConfigur */ @Override public LettucePoolingClientConfiguration build() { - return new DefaultLettucePoolingClientConfiguration(useSsl, verifyPeer, startTls, clientResources, clientOptions, - timeout, shutdownTimeout, poolConfig); + return new DefaultLettucePoolingClientConfiguration(super.build(), poolConfig); + } + } + + /** + * @author Christoph Strobl + */ + class LettucePoolingSslClientConfigurationBuilder extends LettuceSslClientConfigurationBuilder { + + LettucePoolingSslClientConfigurationBuilder(LettucePoolingClientConfigurationBuilder delegate) { + super(delegate); + } + + /* + * (non-Javadoc) + * @see org.springframework.data.redis.connection.lettuce.LettuceClientConfiguration.LettuceSslClientConfigurationBuilder#and() + */ + @Override + LettucePoolingClientConfigurationBuilder and() { + return (LettucePoolingClientConfigurationBuilder) super.and(); + } + + /* + * (non-Javadoc) + * @see org.springframework.data.redis.connection.lettuce.LettuceClientConfiguration.LettuceSslClientConfigurationBuilder#disablePeerVerification() + */ + @Override + LettucePoolingSslClientConfigurationBuilder disablePeerVerification() { + + super.disablePeerVerification(); + return this; + } + + /* + * (non-Javadoc) + * @see org.springframework.data.redis.connection.lettuce.LettuceClientConfiguration.LettuceSslClientConfigurationBuilder#startTls() + */ + @Override + LettucePoolingSslClientConfigurationBuilder startTls() { + + super.startTls(); + return this; + } + + /* + * (non-Javadoc) + * @see org.springframework.data.redis.connection.lettuce.LettuceClientConfiguration.LettuceSslClientConfigurationBuilder#build() + */ + @Override + LettucePoolingClientConfiguration build() { + return (LettucePoolingClientConfiguration) super.build(); } } } diff --git a/src/main/java/org/springframework/data/redis/connection/lettuce/LettucePoolingConnectionProvider.java b/src/main/java/org/springframework/data/redis/connection/lettuce/LettucePoolingConnectionProvider.java index dcdbe05d4..6444db113 100644 --- a/src/main/java/org/springframework/data/redis/connection/lettuce/LettucePoolingConnectionProvider.java +++ b/src/main/java/org/springframework/data/redis/connection/lettuce/LettucePoolingConnectionProvider.java @@ -27,6 +27,7 @@ import org.apache.commons.pool2.impl.GenericObjectPool; import org.apache.commons.pool2.impl.GenericObjectPoolConfig; import org.springframework.beans.factory.DisposableBean; import org.springframework.data.redis.connection.PoolException; +import org.springframework.util.Assert; /** * {@link LettuceConnectionProvider} with connection pooling support. This connection provider holds multiple pools (one @@ -37,6 +38,7 @@ import org.springframework.data.redis.connection.PoolException; * to close the pools. * * @author Mark Paluch + * @author Christoph Strobl * @since 2.0 * @see #getConnection(Class) */ @@ -51,10 +53,13 @@ class LettucePoolingConnectionProvider implements LettuceConnectionProvider, Dis private final Map, GenericObjectPool>> pools = new ConcurrentHashMap<>(32); LettucePoolingConnectionProvider(LettuceConnectionProvider connectionProvider, - LettuceClientConfiguration clientConfiguration) { + LettucePoolingClientConfiguration clientConfiguration) { + + Assert.notNull(connectionProvider, "ConnectionProvider must not be null!"); + Assert.notNull(clientConfiguration, "ClientConfiguration must not be null!"); this.connectionProvider = connectionProvider; - this.poolConfig = ((LettucePoolingClientConfiguration) clientConfiguration).getPoolConfig(); + this.poolConfig = clientConfiguration.getPoolConfig(); } /* @@ -62,8 +67,7 @@ class LettucePoolingConnectionProvider implements LettuceConnectionProvider, Dis * @see org.springframework.data.redis.connection.lettuce.LettuceConnectionProvider#getConnection(java.lang.Class) */ @Override - @SuppressWarnings("rawtypes") - public StatefulConnection getConnection(Class connectionType) { + public > T getConnection(Class connectionType) { GenericObjectPool> pool = pools.computeIfAbsent(connectionType, poolType -> { return ConnectionPoolSupport.createGenericObjectPool(() -> connectionProvider.getConnection(connectionType), @@ -71,11 +75,12 @@ class LettucePoolingConnectionProvider implements LettuceConnectionProvider, Dis }); try { + StatefulConnection connection = pool.borrowObject(); poolRef.put(connection, pool); - return connection; + return connectionType.cast(connection); } catch (Exception e) { throw new PoolException("Could not get a resource from the pool", e); } diff --git a/src/main/java/org/springframework/data/redis/connection/lettuce/LettuceReactiveRedisConnection.java b/src/main/java/org/springframework/data/redis/connection/lettuce/LettuceReactiveRedisConnection.java index 05274debf..d7de15b5f 100644 --- a/src/main/java/org/springframework/data/redis/connection/lettuce/LettuceReactiveRedisConnection.java +++ b/src/main/java/org/springframework/data/redis/connection/lettuce/LettuceReactiveRedisConnection.java @@ -21,7 +21,6 @@ import io.lettuce.core.api.reactive.BaseRedisReactiveCommands; import io.lettuce.core.cluster.api.StatefulRedisClusterConnection; import io.lettuce.core.cluster.api.reactive.RedisClusterReactiveCommands; import io.lettuce.core.codec.RedisCodec; -import org.springframework.data.redis.connection.*; import reactor.core.publisher.Flux; import reactor.core.publisher.Mono; @@ -31,6 +30,7 @@ import java.util.function.Function; import org.reactivestreams.Publisher; import org.springframework.dao.DataAccessException; import org.springframework.dao.InvalidDataAccessResourceUsageException; +import org.springframework.data.redis.connection.*; import org.springframework.util.Assert; /** @@ -58,7 +58,7 @@ class LettuceReactiveRedisConnection implements ReactiveRedisConnection { Assert.notNull(connectionProvider, "LettuceConnectionProvider must not be null!"); this.connectionProvider = connectionProvider; - this.connection = connectionProvider.getConnection(); + this.connection = connectionProvider.getConnection(StatefulConnection.class); } /* diff --git a/src/main/java/org/springframework/data/redis/connection/lettuce/LettuceSentinelConnection.java b/src/main/java/org/springframework/data/redis/connection/lettuce/LettuceSentinelConnection.java index 9cb622f65..ddf1636fe 100644 --- a/src/main/java/org/springframework/data/redis/connection/lettuce/LettuceSentinelConnection.java +++ b/src/main/java/org/springframework/data/redis/connection/lettuce/LettuceSentinelConnection.java @@ -94,7 +94,12 @@ public class LettuceSentinelConnection implements RedisSentinelConnection { public LettuceSentinelConnection(RedisClient redisClient) { Assert.notNull(redisClient, "Cannot create LettuceSentinelConnection using 'null' as client."); - this.provider = t -> redisClient.connectSentinel(); + this.provider = new LettuceConnectionProvider() { + @Override + public > T getConnection(Class t) { + return t.cast(redisClient.connectSentinel()); + } + }; init(); } @@ -106,7 +111,12 @@ public class LettuceSentinelConnection implements RedisSentinelConnection { protected LettuceSentinelConnection(StatefulRedisSentinelConnection connection) { Assert.notNull(connection, "Cannot create LettuceSentinelConnection using 'null' as connection."); - this.provider = t -> connection; + this.provider = new LettuceConnectionProvider() { + @Override + public > T getConnection(Class t) { + return t.cast(connection); + } + }; init(); } @@ -224,7 +234,7 @@ public class LettuceSentinelConnection implements RedisSentinelConnection { private void init() { if (connection == null) { - connection = (StatefulRedisSentinelConnection) provider.getConnection(StatefulRedisSentinelConnection.class); + connection = provider.getConnection(StatefulRedisSentinelConnection.class); } } @@ -263,10 +273,9 @@ public class LettuceSentinelConnection implements RedisSentinelConnection { * (non-Javadoc) * @see org.springframework.data.redis.connection.lettuce.LettuceConnectionProvider#getConnection(java.lang.Class) */ - @SuppressWarnings("rawtypes") @Override - public StatefulConnection getConnection(Class connectionType) { - return redisClient.connectSentinel(); + public > T getConnection(Class connectionType) { + return connectionType.cast(redisClient.connectSentinel()); } /* diff --git a/src/main/java/org/springframework/data/redis/connection/lettuce/StandaloneConnectionProvider.java b/src/main/java/org/springframework/data/redis/connection/lettuce/StandaloneConnectionProvider.java index 502a1860f..1c5fc0151 100644 --- a/src/main/java/org/springframework/data/redis/connection/lettuce/StandaloneConnectionProvider.java +++ b/src/main/java/org/springframework/data/redis/connection/lettuce/StandaloneConnectionProvider.java @@ -26,6 +26,7 @@ import org.springframework.data.redis.connection.lettuce.LettuceConnectionProvid /** * @author Mark Paluch + * @author Christoph Strobl * @since 2.0 */ class StandaloneConnectionProvider implements LettuceConnectionProvider, TargetAware { @@ -43,20 +44,18 @@ class StandaloneConnectionProvider implements LettuceConnectionProvider, TargetA * (non-Javadoc) * @see org.springframework.data.redis.connection.lettuce.LettuceConnectionProvider#getConnection(java.lang.Class) */ - @SuppressWarnings("rawtypes") @Override - public StatefulConnection getConnection(Class connectionType) { - + public > T getConnection(Class connectionType) { if (connectionType.equals(StatefulRedisSentinelConnection.class)) { - return client.connectSentinel(); + return connectionType.cast(client.connectSentinel()); } if (connectionType.equals(StatefulRedisPubSubConnection.class)) { - return client.connectPubSub(codec); + return connectionType.cast(client.connectPubSub(codec)); } if (StatefulConnection.class.isAssignableFrom(connectionType)) { - return client.connect(codec); + return connectionType.cast(client.connect(codec)); } throw new UnsupportedOperationException("Connection type " + connectionType + " not supported!"); @@ -66,20 +65,19 @@ class StandaloneConnectionProvider implements LettuceConnectionProvider, TargetA * (non-Javadoc) * @see org.springframework.data.redis.connection.lettuce.LettuceConnectionProvider.TargetAware#getConnection(java.lang.Class, io.lettuce.core.RedisURI) */ - @SuppressWarnings("rawtypes") @Override - public StatefulConnection getConnection(Class connectionType, RedisURI redisURI) { + public > T getConnection(Class connectionType, RedisURI redisURI) { if (connectionType.equals(StatefulRedisSentinelConnection.class)) { - return client.connectSentinel(redisURI); + return connectionType.cast(client.connectSentinel(redisURI)); } if (connectionType.equals(StatefulRedisPubSubConnection.class)) { - return client.connectPubSub(codec, redisURI); + return connectionType.cast(client.connectPubSub(codec, redisURI)); } if (StatefulConnection.class.isAssignableFrom(connectionType)) { - return client.connect(codec, redisURI); + return connectionType.cast(client.connect(codec, redisURI)); } throw new UnsupportedOperationException("Connection type " + connectionType + " not supported!"); diff --git a/src/test/java/org/springframework/data/redis/connection/lettuce/LettuceClientConfigurationUnitTests.java b/src/test/java/org/springframework/data/redis/connection/lettuce/LettuceClientConfigurationUnitTests.java index 9fd3fc34c..6babd663d 100644 --- a/src/test/java/org/springframework/data/redis/connection/lettuce/LettuceClientConfigurationUnitTests.java +++ b/src/test/java/org/springframework/data/redis/connection/lettuce/LettuceClientConfigurationUnitTests.java @@ -28,6 +28,7 @@ import org.junit.Test; * Unit tests for {@link LettuceClientConfiguration}. * * @author Mark Paluch + * @author Christoph Strobl */ public class LettuceClientConfigurationUnitTests { @@ -36,7 +37,6 @@ public class LettuceClientConfigurationUnitTests { LettuceClientConfiguration configuration = LettuceClientConfiguration.defaultConfiguration(); - assertThat(configuration.isUsePooling()).isFalse(); assertThat(configuration.isUseSsl()).isFalse(); assertThat(configuration.isVerifyPeer()).isTrue(); assertThat(configuration.isStartTls()).isFalse(); @@ -62,7 +62,6 @@ public class LettuceClientConfigurationUnitTests { .shutdownTimeout(Duration.ofHours(2)) // .build(); - assertThat(configuration.isUsePooling()).isFalse(); assertThat(configuration.isUseSsl()).isTrue(); assertThat(configuration.isVerifyPeer()).isFalse(); assertThat(configuration.isStartTls()).isTrue(); diff --git a/src/test/java/org/springframework/data/redis/connection/lettuce/LettuceConnectionFactoryTests.java b/src/test/java/org/springframework/data/redis/connection/lettuce/LettuceConnectionFactoryTests.java index 6bd267365..05438c92b 100644 --- a/src/test/java/org/springframework/data/redis/connection/lettuce/LettuceConnectionFactoryTests.java +++ b/src/test/java/org/springframework/data/redis/connection/lettuce/LettuceConnectionFactoryTests.java @@ -338,7 +338,7 @@ public class LettuceConnectionFactoryTests { GenericObjectPoolConfig poolConfig = new GenericObjectPoolConfig(); - LettuceClientConfiguration configuration = LettucePoolingClientConfiguration.builder().poolConfig(poolConfig).and() + LettuceClientConfiguration configuration = LettucePoolingClientConfiguration.builder().poolConfig(poolConfig) .clientResources(LettuceTestClientResources.getSharedClientResources()).shutdownTimeout(Duration.ZERO).build(); LettuceConnectionFactory factory = new LettuceConnectionFactory(new RedisStandaloneConfiguration(), configuration); diff --git a/src/test/java/org/springframework/data/redis/connection/lettuce/LettucePoolingClientConfigurationUnitTests.java b/src/test/java/org/springframework/data/redis/connection/lettuce/LettucePoolingClientConfigurationUnitTests.java index 68cfdeea0..920faa759 100644 --- a/src/test/java/org/springframework/data/redis/connection/lettuce/LettucePoolingClientConfigurationUnitTests.java +++ b/src/test/java/org/springframework/data/redis/connection/lettuce/LettucePoolingClientConfigurationUnitTests.java @@ -29,6 +29,7 @@ import org.junit.Test; * Unit tests for {@link LettucePoolingClientConfiguration}. * * @author Mark Paluch + * @author Christoph Strobl */ public class LettucePoolingClientConfigurationUnitTests { @@ -37,7 +38,6 @@ public class LettucePoolingClientConfigurationUnitTests { LettucePoolingClientConfiguration configuration = LettucePoolingClientConfiguration.defaultConfiguration(); - assertThat(configuration.isUsePooling()).isTrue(); assertThat(configuration.getPoolConfig()).isNotNull(); assertThat(configuration.isUseSsl()).isFalse(); assertThat(configuration.isVerifyPeer()).isTrue(); @@ -55,19 +55,17 @@ public class LettucePoolingClientConfigurationUnitTests { ClientResources sharedClientResources = LettuceTestClientResources.getSharedClientResources(); GenericObjectPoolConfig poolConfig = new GenericObjectPoolConfig(); - LettucePoolingClientConfiguration configuration = (LettucePoolingClientConfiguration) LettucePoolingClientConfiguration - .builder() // - .poolConfig(poolConfig).and() // + LettucePoolingClientConfiguration configuration = LettucePoolingClientConfiguration.builder() // .useSsl() // .disablePeerVerification() // .startTls().and() // + .poolConfig(poolConfig) // .clientOptions(clientOptions) // .clientResources(sharedClientResources) // .commandTimeout(Duration.ofMinutes(5)) // .shutdownTimeout(Duration.ofHours(2)) // .build(); - assertThat(configuration.isUsePooling()).isTrue(); assertThat(configuration.getPoolConfig()).isEqualTo(poolConfig); assertThat(configuration.isUseSsl()).isTrue(); assertThat(configuration.isVerifyPeer()).isFalse(); diff --git a/src/test/java/org/springframework/data/redis/connection/lettuce/LettuceReactiveCommandsTestsBase.java b/src/test/java/org/springframework/data/redis/connection/lettuce/LettuceReactiveCommandsTestsBase.java index 8521a4408..5f211a949 100644 --- a/src/test/java/org/springframework/data/redis/connection/lettuce/LettuceReactiveCommandsTestsBase.java +++ b/src/test/java/org/springframework/data/redis/connection/lettuce/LettuceReactiveCommandsTestsBase.java @@ -115,11 +115,11 @@ public abstract class LettuceReactiveCommandsTestsBase { public void setUp() { if (nativeConnectionProvider instanceof StandaloneConnectionProvider) { - nativeCommands = ((StatefulRedisConnection) nativeConnectionProvider.getConnection()).sync(); + nativeCommands = nativeConnectionProvider.getConnection(StatefulRedisConnection.class).sync(); this.connection = new LettuceReactiveRedisConnection(connectionProvider); } else { - nativeCommands = ((StatefulRedisClusterConnection) nativeConnectionProvider.getConnection()).sync(); + nativeCommands = nativeConnectionProvider.getConnection(StatefulRedisClusterConnection.class).sync(); this.connection = new LettuceReactiveRedisClusterConnection(connectionProvider); } } diff --git a/src/test/java/org/springframework/data/redis/connection/lettuce/LettuceSentinelIntegrationTests.java b/src/test/java/org/springframework/data/redis/connection/lettuce/LettuceSentinelIntegrationTests.java index 42576aeaf..50bf7129a 100644 --- a/src/test/java/org/springframework/data/redis/connection/lettuce/LettuceSentinelIntegrationTests.java +++ b/src/test/java/org/springframework/data/redis/connection/lettuce/LettuceSentinelIntegrationTests.java @@ -63,7 +63,9 @@ public class LettuceSentinelIntegrationTests extends AbstractConnectionIntegrati public @Rule MinimumRedisVersionRule minimumVersionRule = new MinimumRedisVersionRule(); public LettuceSentinelIntegrationTests(LettuceConnectionFactory connectionFactory, String displayName) { + this.connectionFactory = connectionFactory; + ConnectionFactoryTracker.add(connectionFactory); } @Parameters(name = "{1}") @@ -78,13 +80,11 @@ public class LettuceSentinelIntegrationTests extends AbstractConnectionIntegrati lettuceConnectionFactory.afterPropertiesSet(); LettuceConnectionFactory pooledConnectionFactory = new LettuceConnectionFactory(SENTINEL_CONFIG, - LettucePoolingClientConfiguration.builder().build()); + LettucePoolingClientConfiguration.builder() + .clientResources(LettuceTestClientResources.getSharedClientResources()).build()); pooledConnectionFactory.setShareNativeConnection(false); pooledConnectionFactory.afterPropertiesSet(); - ConnectionFactoryTracker.add(lettuceConnectionFactory); - ConnectionFactoryTracker.add(pooledConnectionFactory); - parameters.add(new Object[] { lettuceConnectionFactory, "Sentinel" }); parameters.add(new Object[] { pooledConnectionFactory, "Sentinel/Pooled" }); diff --git a/src/test/java/org/springframework/data/redis/core/ReactiveOperationsTestParams.java b/src/test/java/org/springframework/data/redis/core/ReactiveOperationsTestParams.java index 816c689d8..ae9c4d195 100644 --- a/src/test/java/org/springframework/data/redis/core/ReactiveOperationsTestParams.java +++ b/src/test/java/org/springframework/data/redis/core/ReactiveOperationsTestParams.java @@ -66,8 +66,8 @@ abstract public class ReactiveOperationsTestParams { .clientResources(LettuceTestClientResources.getSharedClientResources()) // .build(); - LettuceClientConfiguration poolingConfiguration = LettucePoolingClientConfiguration.builder() // - .and().shutdownTimeout(Duration.ZERO) // + LettucePoolingClientConfiguration poolingConfiguration = LettucePoolingClientConfiguration.builder() // + .shutdownTimeout(Duration.ZERO) // .clientResources(LettuceTestClientResources.getSharedClientResources()) // .build();