Skip to content

Commit d0b063f

Browse files
committed
Add lettuce Redis driver autoconfiguration.
Introduce an alternative autoconfiguration if the lettuce Redis driver is available. Add lettuce-specific configuration property options "spring.redis.lettuce.shutdown-timeout" to control the shutdown timeout of the lettuce driver. Add documentation for the properties, the supported drivers, and how to switch between drivers. Jedis stays the default driver even if both libraries are on the class path.
1 parent 98c9744 commit d0b063f

File tree

9 files changed

+205
-25
lines changed

9 files changed

+205
-25
lines changed

spring-boot-actuator/pom.xml

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -243,6 +243,11 @@
243243
<artifactId>jedis</artifactId>
244244
<optional>true</optional>
245245
</dependency>
246+
<dependency>
247+
<groupId>biz.paluch.redis</groupId>
248+
<artifactId>lettuce</artifactId>
249+
<optional>true</optional>
250+
</dependency>
246251
<dependency>
247252
<groupId>org.springframework.amqp</groupId>
248253
<artifactId>spring-rabbit</artifactId>

spring-boot-autoconfigure/pom.xml

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -411,6 +411,11 @@
411411
<artifactId>jedis</artifactId>
412412
<optional>true</optional>
413413
</dependency>
414+
<dependency>
415+
<groupId>biz.paluch.redis</groupId>
416+
<artifactId>lettuce</artifactId>
417+
<optional>true</optional>
418+
</dependency>
414419
<dependency>
415420
<groupId>org.liquibase</groupId>
416421
<artifactId>liquibase-core</artifactId>
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
/*
2+
* Copyright 2012-2016 the original author or authors.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
package org.springframework.boot.autoconfigure.data.redis;
18+
19+
import org.springframework.boot.context.properties.ConfigurationProperties;
20+
21+
/**
22+
* Configuration properties for the lettuce Redis driver.
23+
*
24+
* @author Mark Paluch
25+
*/
26+
@ConfigurationProperties(prefix = "spring.redis.lettuce")
27+
class LettuceRedisProperties {
28+
29+
/**
30+
* Shutdown timeout in milliseconds for lettuce.
31+
*/
32+
private int shutdownTimeout = 2000;
33+
34+
public int getShutdownTimeout() {
35+
return this.shutdownTimeout;
36+
}
37+
38+
public void setShutdownTimeout(int shutdownTimeout) {
39+
this.shutdownTimeout = shutdownTimeout;
40+
}
41+
}

spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/data/redis/RedisAutoConfiguration.java

Lines changed: 95 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@
2020
import java.util.ArrayList;
2121
import java.util.List;
2222

23+
import com.lambdaworks.redis.RedisClient;
2324
import org.apache.commons.pool2.impl.GenericObjectPool;
2425
import redis.clients.jedis.Jedis;
2526
import redis.clients.jedis.JedisPoolConfig;
@@ -40,6 +41,8 @@
4041
import org.springframework.data.redis.connection.RedisSentinelConfiguration;
4142
import org.springframework.data.redis.connection.jedis.JedisConnection;
4243
import org.springframework.data.redis.connection.jedis.JedisConnectionFactory;
44+
import org.springframework.data.redis.connection.lettuce.LettuceConnection;
45+
import org.springframework.data.redis.connection.lettuce.LettuceConnectionFactory;
4346
import org.springframework.data.redis.core.RedisOperations;
4447
import org.springframework.data.redis.core.RedisTemplate;
4548
import org.springframework.data.redis.core.StringRedisTemplate;
@@ -55,9 +58,10 @@
5558
* @author Christoph Strobl
5659
* @author Phillip Webb
5760
* @author Eddú Meléndez
61+
* @author Mark Paluch
5862
*/
5963
@Configuration
60-
@ConditionalOnClass({ JedisConnection.class, RedisOperations.class, Jedis.class })
64+
@ConditionalOnClass({ RedisOperations.class })
6165
@EnableConfigurationProperties
6266
public class RedisAutoConfiguration {
6367

@@ -67,6 +71,12 @@ public RedisProperties redisProperties() {
6771
return new RedisProperties();
6872
}
6973

74+
@Bean(name = "org.springframework.autoconfigure.redis.LettuceRedisProperties")
75+
@ConditionalOnMissingBean
76+
public LettuceRedisProperties lettuceRedisProperties() {
77+
return new LettuceRedisProperties();
78+
}
79+
7080
/**
7181
* Base class for Redis configurations.
7282
*/
@@ -81,20 +91,6 @@ protected static abstract class AbstractRedisConfiguration {
8191
@Autowired(required = false)
8292
private RedisClusterConfiguration clusterConfiguration;
8393

84-
protected final JedisConnectionFactory applyProperties(
85-
JedisConnectionFactory factory) {
86-
factory.setHostName(this.properties.getHost());
87-
factory.setPort(this.properties.getPort());
88-
if (this.properties.getPassword() != null) {
89-
factory.setPassword(this.properties.getPassword());
90-
}
91-
factory.setDatabase(this.properties.getDatabase());
92-
if (this.properties.getTimeout() > 0) {
93-
factory.setTimeout(this.properties.getTimeout());
94-
}
95-
return factory;
96-
}
97-
9894
protected final RedisSentinelConfiguration getSentinelConfig() {
9995
if (this.sentinelConfiguration != null) {
10096
return this.sentinelConfiguration;
@@ -146,16 +142,41 @@ private List<RedisNode> createSentinels(Sentinel sentinel) {
146142
}
147143
return nodes;
148144
}
145+
}
146+
147+
/**
148+
* Base class for Redis configurations using the Jedis driver.
149+
*/
150+
protected static abstract class AbstractJedisRedisConfiguration
151+
extends AbstractRedisConfiguration {
152+
153+
@Autowired
154+
protected RedisProperties properties;
155+
156+
protected final JedisConnectionFactory applyProperties(
157+
JedisConnectionFactory factory) {
158+
factory.setHostName(this.properties.getHost());
159+
factory.setPort(this.properties.getPort());
160+
if (this.properties.getPassword() != null) {
161+
factory.setPassword(this.properties.getPassword());
162+
}
163+
factory.setDatabase(this.properties.getDatabase());
164+
if (this.properties.getTimeout() > 0) {
165+
factory.setTimeout(this.properties.getTimeout());
166+
}
167+
return factory;
168+
}
149169

150170
}
151171

152172
/**
153173
* Redis connection configuration.
154174
*/
155175
@Configuration
176+
@ConditionalOnClass({ JedisConnection.class, Jedis.class })
156177
@ConditionalOnMissingClass("org.apache.commons.pool2.impl.GenericObjectPool")
157-
protected static class RedisConnectionConfiguration
158-
extends AbstractRedisConfiguration {
178+
protected static class JedisRedisConnectionConfiguration
179+
extends AbstractJedisRedisConfiguration {
159180

160181
@Bean
161182
@ConditionalOnMissingBean(RedisConnectionFactory.class)
@@ -179,9 +200,9 @@ private JedisConnectionFactory createJedisConnectionFactory() {
179200
* Redis pooled connection configuration.
180201
*/
181202
@Configuration
182-
@ConditionalOnClass(GenericObjectPool.class)
183-
protected static class RedisPooledConnectionConfiguration
184-
extends AbstractRedisConfiguration {
203+
@ConditionalOnClass({ GenericObjectPool.class, JedisConnection.class, Jedis.class })
204+
protected static class JedisRedisPooledConnectionConfiguration
205+
extends AbstractJedisRedisConfiguration {
185206

186207
@Bean
187208
@ConditionalOnMissingBean(RedisConnectionFactory.class)
@@ -215,6 +236,60 @@ private JedisPoolConfig jedisPoolConfig() {
215236

216237
}
217238

239+
/**
240+
* Base class for Redis configurations using the Jedis driver.
241+
*/
242+
protected static abstract class AbstractLettuceRedisConfiguration
243+
extends AbstractRedisConfiguration {
244+
245+
@Autowired
246+
protected LettuceRedisProperties lettuceRedisProperties;
247+
248+
protected final LettuceConnectionFactory applyProperties(
249+
LettuceConnectionFactory factory) {
250+
factory.setHostName(this.properties.getHost());
251+
factory.setPort(this.properties.getPort());
252+
if (this.properties.getPassword() != null) {
253+
factory.setPassword(this.properties.getPassword());
254+
}
255+
factory.setDatabase(this.properties.getDatabase());
256+
if (this.properties.getTimeout() > 0) {
257+
factory.setTimeout(this.properties.getTimeout());
258+
}
259+
if (this.lettuceRedisProperties.getShutdownTimeout() > 0) {
260+
factory.setShutdownTimeout(this.lettuceRedisProperties.getShutdownTimeout());
261+
}
262+
return factory;
263+
}
264+
}
265+
266+
/**
267+
* Redis connection configuration using the Lettuce driver.
268+
*/
269+
@Configuration
270+
@ConditionalOnClass({ LettuceConnection.class, RedisClient.class })
271+
@ConditionalOnMissingClass("redis.clients.jedis.Jedis")
272+
protected static class LettuceRedisConnectionConfiguration
273+
extends AbstractLettuceRedisConfiguration {
274+
275+
@Bean
276+
@ConditionalOnMissingBean(RedisConnectionFactory.class)
277+
public LettuceConnectionFactory redisConnectionFactory()
278+
throws UnknownHostException {
279+
return applyProperties(createLettuceConnectionFactory());
280+
}
281+
282+
private LettuceConnectionFactory createLettuceConnectionFactory() {
283+
if (getSentinelConfig() != null) {
284+
return new LettuceConnectionFactory(getSentinelConfig());
285+
}
286+
if (getClusterConfiguration() != null) {
287+
return new LettuceConnectionFactory(getClusterConfiguration());
288+
}
289+
return new LettuceConnectionFactory();
290+
}
291+
}
292+
218293
/**
219294
* Standard Redis configuration.
220295
*/

spring-boot-dependencies/pom.xml

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -111,6 +111,7 @@
111111
<jtds.version>1.3.1</jtds.version>
112112
<junit.version>4.12</junit.version>
113113
<liquibase.version>3.4.2</liquibase.version>
114+
<lettuce.version>3.4.2.Final</lettuce.version>
114115
<log4j2.version>2.5</log4j2.version>
115116
<logback.version>1.1.5</logback.version>
116117
<lombok.version>1.16.6</lombok.version>
@@ -2098,6 +2099,11 @@
20982099
<artifactId>jedis</artifactId>
20992100
<version>${jedis.version}</version>
21002101
</dependency>
2102+
<dependency>
2103+
<groupId>biz.paluch.redis</groupId>
2104+
<artifactId>lettuce</artifactId>
2105+
<version>${lettuce.version}</version>
2106+
</dependency>
21012107
<dependency>
21022108
<groupId>wsdl4j</groupId>
21032109
<artifactId>wsdl4j</artifactId>

spring-boot-docs/pom.xml

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -558,6 +558,11 @@
558558
<artifactId>jedis</artifactId>
559559
<optional>true</optional>
560560
</dependency>
561+
<dependency>
562+
<groupId>biz.paluch.redis</groupId>
563+
<artifactId>lettuce</artifactId>
564+
<optional>true</optional>
565+
</dependency>
561566
</dependencies>
562567
<profiles>
563568
<profile>

spring-boot-docs/src/main/asciidoc/appendix-application-properties.adoc

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -685,7 +685,7 @@ content into your application; rather pick only the properties that you need.
685685
spring.mongodb.embedded.features=SYNC_DELAY # Comma-separated list of features to enable.
686686
spring.mongodb.embedded.version=2.6.10 # Version of Mongo to use.
687687
688-
# REDIS ({sc-spring-boot-autoconfigure}/redis/RedisProperties.{sc-ext}[RedisProperties])
688+
# REDIS ({sc-spring-boot-autoconfigure}/data/redis/RedisProperties.{sc-ext}[RedisProperties])
689689
spring.redis.cluster.max-redirects= # Maximum number of redirects to follow when executing commands across the cluster.
690690
spring.redis.cluster.nodes= # Comma-separated list of "host:port" pairs to bootstrap from.
691691
spring.redis.database=0 # Database index used by the connection factory.
@@ -700,6 +700,8 @@ content into your application; rather pick only the properties that you need.
700700
spring.redis.sentinel.nodes= # Comma-separated list of host:port pairs.
701701
spring.redis.timeout=0 # Connection timeout in milliseconds.
702702
703+
# REDIS LETTUCE DRIVER ({sc-spring-boot-autoconfigure}/data/redis/LettuceRedisProperties.{sc-ext}[LettuceRedisProperties])
704+
spring.redis.lettuce.shutdown-timeout=2000 # Shutdown timeout in milliseconds.
703705
704706
# ----------------------------------------
705707
# INTEGRATION PROPERTIES

spring-boot-docs/src/main/asciidoc/howto.adoc

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2775,3 +2775,44 @@ but the rest of it is normal for a Spring application in Servlet 2.5. Example:
27752775
In this example we are using a single application context (the one created by the context
27762776
listener) and attaching it to the `DispatcherServlet` using an init parameter. This is
27772777
normal in a Spring Boot application (you normally only have one application context).
2778+
2779+
[[howto-use-lettuce-instead-of-jedis]]
2780+
=== Use Lettuce instead of Jedis
2781+
The Spring Boot Redis starter (`spring-boot-starter-data-redis` in particular) uses
2782+
https://github.com/xetorthio/jedis/[Jedis] by default. You need to exclude that dependency
2783+
and include the https://github.com/mp911de/lettuce/[Lettuce] one instead. Spring Boot provides a managed dependency
2784+
to help make this process as easy as possible.
2785+
2786+
Example in Maven:
2787+
2788+
[source,xml,indent=0,subs="verbatim,quotes,attributes"]
2789+
----
2790+
<dependency>
2791+
<groupId>org.springframework.boot</groupId>
2792+
<artifactId>spring-boot-starter-data-redis</artifactId>
2793+
<exclusions>
2794+
<exclusion>
2795+
<groupId>redis.clients</groupId>
2796+
<artifactId>jedis</artifactId>
2797+
</exclusion>
2798+
</exclusions>
2799+
</dependency>
2800+
<dependency>
2801+
<groupId>biz.paluch.redis</groupId>
2802+
<artifactId>lettuce</artifactId>
2803+
</dependency>
2804+
----
2805+
2806+
Example in Gradle:
2807+
2808+
[source,groovy,indent=0,subs="verbatim,quotes,attributes"]
2809+
----
2810+
configurations {
2811+
compile.exclude module: "jedis"
2812+
}
2813+
2814+
dependencies {
2815+
compile("biz.paluch.redis:lettuce:{lettuce.version}")
2816+
// ...
2817+
}
2818+
----

spring-boot-docs/src/main/asciidoc/spring-boot-features.adoc

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2761,10 +2761,10 @@ http://projects.spring.io/spring-data[projects.spring.io/spring-data].
27612761
=== Redis
27622762
http://redis.io/[Redis] is a cache, message broker and richly-featured key-value store.
27632763
Spring Boot offers basic auto-configuration for the
2764-
https://github.com/xetorthio/jedis/[Jedis] client library and abstractions on top of it
2765-
provided by https://github.com/spring-projects/spring-data-redis[Spring Data Redis]. There
2766-
is a `spring-boot-starter-data-redis` '`Starter POM`' for collecting the dependencies in a
2767-
convenient way.
2764+
https://github.com/xetorthio/jedis/[Jedis] and https://github.com/mp911de/lettuce/[Lettuce]
2765+
client libraries and abstractions on top of it provided by https://github.com/spring-projects/spring-data-redis[Spring Data Redis].
2766+
There is a `spring-boot-starter-data-redis` '`Starter POM`' for collecting the dependencies in a
2767+
convenient way that uses https://github.com/xetorthio/jedis/[Jedis] by default.
27682768

27692769

27702770

0 commit comments

Comments
 (0)