From 5760555c57aed22610409461261babab408c9a31 Mon Sep 17 00:00:00 2001 From: Mark Paluch Date: Tue, 10 Oct 2017 16:15:05 +0200 Subject: [PATCH] #299 - Migrate Redis examples to Lettuce. We now use Lettuce API instead of Jedis to align with Boot's driver choice. --- redis/repositories/README.md | 6 +- .../ApplicationConfiguration.java | 9 +-- redis/sentinel/README.md | 2 +- .../sentinel/RedisSentinelApplication.java | 4 +- redis/util/pom.xml | 4 +- .../test/util/ManagedClientResources.java | 62 +++++++++++++++++++ .../test/util/RequiresRedisSentinel.java | 56 ++++++++--------- .../redis/test/util/RequiresRedisServer.java | 19 ++++-- 8 files changed, 116 insertions(+), 46 deletions(-) create mode 100644 redis/util/src/main/java/example/springdata/redis/test/util/ManagedClientResources.java diff --git a/redis/repositories/README.md b/redis/repositories/README.md index bfd6a98be..23ed11098 100644 --- a/redis/repositories/README.md +++ b/redis/repositories/README.md @@ -74,7 +74,7 @@ redis/src $ ./redis-cli keys * ## Configuration ## -The below configuration uses [Jedis](https://github.com/xetorthio/jedis) to connect to Redis on its default port. Please note the usage of `@EnableRedisRepositories` to create `Repository` instances. +The below configuration uses [Lettuce](https://github.com/lettuce-io/lettuce-core) to connect to Redis on its default port. Please note the usage of `@EnableRedisRepositories` to create `Repository` instances. ```java @Configuration @@ -83,13 +83,13 @@ class AppConfig { @Bean RedisConnectionFactory connectionFactory() { - return new JedisConnectionFactory(); + return new LettuceConnectionFactory(); } @Bean RedisTemplate redisTemplate(RedisConnectionFactory connectionFactory) { - RedisTemplate template = new RedisTemplate(); + RedisTemplate template = new RedisTemplate<>(); template.setConnectionFactory(connectionFactory); return template; diff --git a/redis/repositories/src/main/java/example/springdata/redis/repositories/ApplicationConfiguration.java b/redis/repositories/src/main/java/example/springdata/redis/repositories/ApplicationConfiguration.java index 53054e8b7..82ea0f530 100644 --- a/redis/repositories/src/main/java/example/springdata/redis/repositories/ApplicationConfiguration.java +++ b/redis/repositories/src/main/java/example/springdata/redis/repositories/ApplicationConfiguration.java @@ -1,5 +1,5 @@ /* - * Copyright 2016 the original author or authors. + * Copyright 2016-2017 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. @@ -18,12 +18,13 @@ import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.data.redis.connection.RedisConnectionFactory; -import org.springframework.data.redis.connection.jedis.JedisConnectionFactory; +import org.springframework.data.redis.connection.lettuce.LettuceConnectionFactory; import org.springframework.data.redis.core.RedisTemplate; import org.springframework.data.redis.repository.configuration.EnableRedisRepositories; /** * @author Christoph Strobl + * @author Mark Paluch */ @Configuration @EnableRedisRepositories @@ -31,13 +32,13 @@ public class ApplicationConfiguration { @Bean RedisConnectionFactory connectionFactory() { - return new JedisConnectionFactory(); + return new LettuceConnectionFactory(); } @Bean RedisTemplate redisTemplate(RedisConnectionFactory connectionFactory) { - RedisTemplate template = new RedisTemplate(); + RedisTemplate template = new RedisTemplate<>(); template.setConnectionFactory(connectionFactory); return template; diff --git a/redis/sentinel/README.md b/redis/sentinel/README.md index b3758789a..99c696bd3 100644 --- a/redis/sentinel/README.md +++ b/redis/sentinel/README.md @@ -15,7 +15,7 @@ public class RedisSentinelApplicationConfig { @Bean public RedisConnectionFactory connectionFactory() { - return new JedisConnectionFactory(sentinelConfig()); + return new LettuceConnectionFactory(sentinelConfig(), LettuceClientConfiguration.defaultConfiguration()); } @Bean diff --git a/redis/sentinel/src/main/java/example/springdata/redis/sentinel/RedisSentinelApplication.java b/redis/sentinel/src/main/java/example/springdata/redis/sentinel/RedisSentinelApplication.java index ebbd6ece8..bcc9af91b 100644 --- a/redis/sentinel/src/main/java/example/springdata/redis/sentinel/RedisSentinelApplication.java +++ b/redis/sentinel/src/main/java/example/springdata/redis/sentinel/RedisSentinelApplication.java @@ -24,6 +24,7 @@ import org.springframework.context.annotation.Configuration; import org.springframework.data.redis.connection.RedisConnectionFactory; import org.springframework.data.redis.connection.RedisSentinelConfiguration; +import org.springframework.data.redis.connection.lettuce.LettuceClientConfiguration; import org.springframework.data.redis.connection.lettuce.LettuceConnectionFactory; import org.springframework.data.redis.core.StringRedisTemplate; import org.springframework.util.StopWatch; @@ -31,6 +32,7 @@ /** * @author Christoph Strobl * @author Oliver Gierke + * @author Mark Paluch */ @Configuration public class RedisSentinelApplication { @@ -74,7 +76,7 @@ public static void main(String[] args) throws Exception { } public @Bean RedisConnectionFactory connectionFactory() { - return new LettuceConnectionFactory(sentinelConfig()); + return new LettuceConnectionFactory(sentinelConfig(), LettuceClientConfiguration.defaultConfiguration()); } public @Bean RedisSentinelConfiguration sentinelConfig() { diff --git a/redis/util/pom.xml b/redis/util/pom.xml index 28a625dec..293fe4cbc 100644 --- a/redis/util/pom.xml +++ b/redis/util/pom.xml @@ -20,8 +20,8 @@ - redis.clients - jedis + io.lettuce + lettuce-core diff --git a/redis/util/src/main/java/example/springdata/redis/test/util/ManagedClientResources.java b/redis/util/src/main/java/example/springdata/redis/test/util/ManagedClientResources.java new file mode 100644 index 000000000..ac035978e --- /dev/null +++ b/redis/util/src/main/java/example/springdata/redis/test/util/ManagedClientResources.java @@ -0,0 +1,62 @@ +/* + * Copyright 2017 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 + * + * http://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 example.springdata.redis.test.util; + +import io.lettuce.core.resource.ClientResources; +import io.lettuce.core.resource.DefaultClientResources; + +import java.util.concurrent.TimeUnit; +import java.util.concurrent.atomic.AtomicReference; + +/** + * Utility to keep track of a single {@link ClientResources} instance used from test rules to prevent costly + * creation/disposal of threading resources. + * + * @author Mark Paluch + */ +class ManagedClientResources { + + private static final ManagedClientResources instance = new ManagedClientResources(); + + private final AtomicReference clientResources = new AtomicReference<>(); + + /** + * Obtain a managed instance of {@link ClientResources}. Allocates an instance if {@link ManagedClientResources} was + * not initialized already. + * + * @return the {@link ClientResources}. + */ + static ClientResources getClientResources() { + + AtomicReference ref = instance.clientResources; + + ClientResources clientResources = ref.get(); + if (clientResources != null) { + return clientResources; + } + + clientResources = DefaultClientResources.create(); + + if (ref.compareAndSet(null, clientResources)) { + return clientResources; + } + + clientResources.shutdown(0, 0, TimeUnit.SECONDS); + + return ref.get(); + } + +} diff --git a/redis/util/src/main/java/example/springdata/redis/test/util/RequiresRedisSentinel.java b/redis/util/src/main/java/example/springdata/redis/test/util/RequiresRedisSentinel.java index 836316630..36fa8ffcb 100644 --- a/redis/util/src/main/java/example/springdata/redis/test/util/RequiresRedisSentinel.java +++ b/redis/util/src/main/java/example/springdata/redis/test/util/RequiresRedisSentinel.java @@ -1,5 +1,5 @@ /* - * Copyright 2014 the original author or authors. + * Copyright 2014-2017 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. @@ -15,6 +15,12 @@ */ package example.springdata.redis.test.util; +import io.lettuce.core.RedisClient; +import io.lettuce.core.RedisURI; +import io.lettuce.core.api.StatefulRedisConnection; + +import java.time.Duration; + import org.junit.internal.AssumptionViolatedException; import org.junit.rules.TestRule; import org.junit.runner.Description; @@ -22,10 +28,9 @@ import org.springframework.data.redis.connection.RedisNode; import org.springframework.data.redis.connection.RedisSentinelConfiguration; -import redis.clients.jedis.Jedis; - /** * @author Christoph Strobl + * @author Mark Paluch */ public class RequiresRedisSentinel implements TestRule { @@ -44,8 +49,8 @@ protected RequiresRedisSentinel(RedisSentinelConfiguration config) { } /** - * Create new {@link RedisSentinelRule} for given {@link RedisSentinelConfiguration}. - * + * Create new {@link RequiresRedisSentinel} for given {@link RedisSentinelConfiguration}. + * * @param config * @return */ @@ -54,8 +59,8 @@ public static RequiresRedisSentinel forConfig(RedisSentinelConfiguration config) } /** - * Create new {@link RedisSentinelRule} using default configuration. - * + * Create new {@link RequiresRedisSentinel} using default configuration. + * * @return */ public static RequiresRedisSentinel withDefaultConfig() { @@ -70,7 +75,7 @@ public RequiresRedisSentinel sentinelsDisabled() { /** * Verifies all {@literal Sentinel} nodes are available. - * + * * @return */ public RequiresRedisSentinel allActive() { @@ -81,7 +86,7 @@ public RequiresRedisSentinel allActive() { /** * Verifies at least one {@literal Sentinel} node is available. - * + * * @return */ public RequiresRedisSentinel oneActive() { @@ -93,7 +98,7 @@ public RequiresRedisSentinel oneActive() { /** * Will only check {@link RedisSentinelConfiguration} configuration in case {@link RequiresRedisSentinel} is detected * on test method. - * + * * @return */ public RequiresRedisSentinel dynamicModeSelection() { @@ -138,9 +143,9 @@ private void verify(SentinelsAvailable verificationMode) { if (failed > 0) { if (SentinelsAvailable.ALL_ACTIVE.equals(verificationMode)) { - throw new AssumptionViolatedException(String.format( - "Expected all Redis Sentinels to respone but %s of %s did not responde", failed, sentinelConfig - .getSentinels().size())); + throw new AssumptionViolatedException( + String.format("Expected all Redis Sentinels to respone but %s of %s did not responde", failed, + sentinelConfig.getSentinels().size())); } if (SentinelsAvailable.ONE_ACTIVE.equals(verificationMode) && sentinelConfig.getSentinels().size() - 1 < failed) { @@ -150,32 +155,23 @@ private void verify(SentinelsAvailable verificationMode) { } if (SentinelsAvailable.NONE_ACTIVE.equals(verificationMode) && failed != sentinelConfig.getSentinels().size()) { - throw new AssumptionViolatedException(String.format( - "Expected to have no sentinels online but found that %s are still alive.", (sentinelConfig.getSentinels() - .size() - failed))); + throw new AssumptionViolatedException( + String.format("Expected to have no sentinels online but found that %s are still alive.", + (sentinelConfig.getSentinels().size() - failed))); } } private boolean isAvailable(RedisNode node) { - Jedis jedis = null; + RedisClient redisClient = RedisClient.create(ManagedClientResources.getClientResources(), + RedisURI.create(node.getHost(), node.getPort())); - try { - jedis = new Jedis(node.getHost(), node.getPort()); - jedis.connect(); - jedis.ping(); + try (StatefulRedisConnection connection = redisClient.connect()) { + connection.sync().ping(); } catch (Exception e) { return false; } finally { - - if (jedis != null) { - try { - jedis.disconnect(); - jedis.close(); - } catch (Exception e) { - e.printStackTrace(); - } - } + redisClient.shutdown(Duration.ZERO, Duration.ZERO); } return true; diff --git a/redis/util/src/main/java/example/springdata/redis/test/util/RequiresRedisServer.java b/redis/util/src/main/java/example/springdata/redis/test/util/RequiresRedisServer.java index 6e607eecb..75a016725 100644 --- a/redis/util/src/main/java/example/springdata/redis/test/util/RequiresRedisServer.java +++ b/redis/util/src/main/java/example/springdata/redis/test/util/RequiresRedisServer.java @@ -15,14 +15,17 @@ */ package example.springdata.redis.test.util; -import redis.clients.jedis.Jedis; +import io.lettuce.core.RedisClient; +import io.lettuce.core.RedisURI; +import io.lettuce.core.api.StatefulRedisConnection; import java.net.InetSocketAddress; import java.net.Socket; +import java.time.Duration; import org.junit.AssumptionViolatedException; import org.junit.rules.ExternalResource; -import org.springframework.data.redis.connection.jedis.JedisConverters; +import org.springframework.data.redis.connection.lettuce.LettuceConverters; import org.springframework.data.util.Version; import org.springframework.util.Assert; import org.springframework.util.StringUtils; @@ -107,16 +110,22 @@ protected void before() throws Throwable { return; } - try (Jedis jedis = new Jedis(host, port)) { + RedisClient redisClient = RedisClient.create(ManagedClientResources.getClientResources(), + RedisURI.create(host, port)); - String infoServer = jedis.info("server"); - String redisVersion = JedisConverters.stringToProps().convert(infoServer).getProperty("redis_version"); + try (StatefulRedisConnection connection = redisClient.connect()) { + + String infoServer = connection.sync().info("server"); + String redisVersion = LettuceConverters.stringToProps().convert(infoServer).getProperty("redis_version"); Version runningVersion = Version.parse(redisVersion); if (runningVersion.isLessThan(requiredVersion)) { throw new AssumptionViolatedException(String .format("This test requires Redis version %s but you run version %s", requiredVersion, runningVersion)); } + + } finally { + redisClient.shutdown(Duration.ZERO, Duration.ZERO); } } }