#299 - Migrate Redis examples to Lettuce.

We now use Lettuce API instead of Jedis to align with Boot's driver choice.
This commit is contained in:
Mark Paluch
2017-10-10 16:15:05 +02:00
parent ffc33fcf92
commit 5760555c57
8 changed files with 116 additions and 46 deletions

View File

@@ -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<byte[], byte[]> template = new RedisTemplate<byte[], byte[]>();
RedisTemplate<byte[], byte[]> template = new RedisTemplate<>();
template.setConnectionFactory(connectionFactory);
return template;

View File

@@ -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 @@ package example.springdata.redis.repositories;
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<byte[], byte[]> template = new RedisTemplate<byte[], byte[]>();
RedisTemplate<byte[], byte[]> template = new RedisTemplate<>();
template.setConnectionFactory(connectionFactory);
return template;

View File

@@ -15,7 +15,7 @@ public class RedisSentinelApplicationConfig {
@Bean
public RedisConnectionFactory connectionFactory() {
return new JedisConnectionFactory(sentinelConfig());
return new LettuceConnectionFactory(sentinelConfig(), LettuceClientConfiguration.defaultConfiguration());
}
@Bean

View File

@@ -24,6 +24,7 @@ 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.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 @@ import org.springframework.util.StopWatch;
/**
* @author Christoph Strobl
* @author Oliver Gierke
* @author Mark Paluch
*/
@Configuration
public class RedisSentinelApplication {
@@ -74,7 +76,7 @@ public class RedisSentinelApplication {
}
public @Bean RedisConnectionFactory connectionFactory() {
return new LettuceConnectionFactory(sentinelConfig());
return new LettuceConnectionFactory(sentinelConfig(), LettuceClientConfiguration.defaultConfiguration());
}
public @Bean RedisSentinelConfiguration sentinelConfig() {

View File

@@ -20,8 +20,8 @@
</dependency>
<dependency>
<groupId>redis.clients</groupId>
<artifactId>jedis</artifactId>
<groupId>io.lettuce</groupId>
<artifactId>lettuce-core</artifactId>
</dependency>
<dependency>

View File

@@ -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> 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<ClientResources> 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();
}
}

View File

@@ -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.junit.runners.model.Statement;
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 @@ public class RequiresRedisSentinel implements TestRule {
}
/**
* Create new {@link RedisSentinelRule} for given {@link RedisSentinelConfiguration}.
*
* Create new {@link RequiresRedisSentinel} for given {@link RedisSentinelConfiguration}.
*
* @param config
* @return
*/
@@ -54,8 +59,8 @@ public class RequiresRedisSentinel implements TestRule {
}
/**
* Create new {@link RedisSentinelRule} using default configuration.
*
* Create new {@link RequiresRedisSentinel} using default configuration.
*
* @return
*/
public static RequiresRedisSentinel withDefaultConfig() {
@@ -70,7 +75,7 @@ public class RequiresRedisSentinel implements TestRule {
/**
* Verifies all {@literal Sentinel} nodes are available.
*
*
* @return
*/
public RequiresRedisSentinel allActive() {
@@ -81,7 +86,7 @@ public class RequiresRedisSentinel implements TestRule {
/**
* Verifies at least one {@literal Sentinel} node is available.
*
*
* @return
*/
public RequiresRedisSentinel oneActive() {
@@ -93,7 +98,7 @@ public class RequiresRedisSentinel implements TestRule {
/**
* Will only check {@link RedisSentinelConfiguration} configuration in case {@link RequiresRedisSentinel} is detected
* on test method.
*
*
* @return
*/
public RequiresRedisSentinel dynamicModeSelection() {
@@ -138,9 +143,9 @@ public class RequiresRedisSentinel implements TestRule {
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 @@ public class RequiresRedisSentinel implements TestRule {
}
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<String, String> 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;

View File

@@ -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 @@ public class RequiresRedisServer extends ExternalResource {
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<String, String> 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);
}
}
}