Skip to content

Commit de00974

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 322b1b2 commit de00974

File tree

9 files changed

+235
-19
lines changed

9 files changed

+235
-19
lines changed

spring-boot-actuator/pom.xml

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -248,6 +248,11 @@
248248
<artifactId>jedis</artifactId>
249249
<optional>true</optional>
250250
</dependency>
251+
<dependency>
252+
<groupId>biz.paluch.redis</groupId>
253+
<artifactId>lettuce</artifactId>
254+
<optional>true</optional>
255+
</dependency>
251256
<dependency>
252257
<groupId>org.springframework.amqp</groupId>
253258
<artifactId>spring-rabbit</artifactId>

spring-boot-autoconfigure/pom.xml

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -427,6 +427,11 @@
427427
<artifactId>jedis</artifactId>
428428
<optional>true</optional>
429429
</dependency>
430+
<dependency>
431+
<groupId>biz.paluch.redis</groupId>
432+
<artifactId>lettuce</artifactId>
433+
<optional>true</optional>
434+
</dependency>
430435
<dependency>
431436
<groupId>org.liquibase</groupId>
432437
<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: 126 additions & 15 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;
@@ -39,6 +40,8 @@
3940
import org.springframework.data.redis.connection.RedisSentinelConfiguration;
4041
import org.springframework.data.redis.connection.jedis.JedisConnection;
4142
import org.springframework.data.redis.connection.jedis.JedisConnectionFactory;
43+
import org.springframework.data.redis.connection.lettuce.LettuceConnection;
44+
import org.springframework.data.redis.connection.lettuce.LettuceConnectionFactory;
4245
import org.springframework.data.redis.core.RedisOperations;
4346
import org.springframework.data.redis.core.RedisTemplate;
4447
import org.springframework.data.redis.core.StringRedisTemplate;
@@ -55,9 +58,10 @@
5558
* @author Phillip Webb
5659
* @author Eddú Meléndez
5760
* @author Stephane Nicoll
61+
* @author Mark Paluch
5862
*/
5963
@Configuration
60-
@ConditionalOnClass({ JedisConnection.class, RedisOperations.class, Jedis.class })
64+
@ConditionalOnClass({ RedisOperations.class,})
6165
@EnableConfigurationProperties(RedisProperties.class)
6266
public class RedisAutoConfiguration {
6367

@@ -89,20 +93,6 @@ public JedisConnectionFactory redisConnectionFactory()
8993
return applyProperties(createJedisConnectionFactory());
9094
}
9195

92-
protected final JedisConnectionFactory applyProperties(
93-
JedisConnectionFactory factory) {
94-
factory.setHostName(this.properties.getHost());
95-
factory.setPort(this.properties.getPort());
96-
if (this.properties.getPassword() != null) {
97-
factory.setPassword(this.properties.getPassword());
98-
}
99-
factory.setDatabase(this.properties.getDatabase());
100-
if (this.properties.getTimeout() > 0) {
101-
factory.setTimeout(this.properties.getTimeout());
102-
}
103-
return factory;
104-
}
105-
10696
protected final RedisSentinelConfiguration getSentinelConfig() {
10797
if (this.sentinelConfiguration != null) {
10898
return this.sentinelConfiguration;
@@ -154,6 +144,73 @@ private List<RedisNode> createSentinels(Sentinel sentinel) {
154144
}
155145
return nodes;
156146
}
147+
}
148+
149+
/**
150+
* Base class for Redis configurations using the Jedis driver.
151+
*/
152+
protected static abstract class AbstractJedisRedisConfiguration
153+
extends AbstractRedisConfiguration {
154+
155+
@Autowired
156+
protected RedisProperties properties;
157+
158+
protected final JedisConnectionFactory applyProperties(
159+
JedisConnectionFactory factory) {
160+
factory.setHostName(this.properties.getHost());
161+
factory.setPort(this.properties.getPort());
162+
if (this.properties.getPassword() != null) {
163+
factory.setPassword(this.properties.getPassword());
164+
}
165+
factory.setDatabase(this.properties.getDatabase());
166+
if (this.properties.getTimeout() > 0) {
167+
factory.setTimeout(this.properties.getTimeout());
168+
}
169+
return factory;
170+
}
171+
172+
}
173+
174+
/**
175+
* Redis connection configuration.
176+
*/
177+
@Configuration
178+
@ConditionalOnMissingClass("org.apache.commons.pool2.impl.GenericObjectPool")
179+
protected static class RedisConnectionConfiguration
180+
extends AbstractRedisConfiguration {
181+
182+
@Bean
183+
@ConditionalOnMissingBean(RedisConnectionFactory.class)
184+
public JedisConnectionFactory redisConnectionFactory()
185+
throws UnknownHostException {
186+
return applyProperties(createJedisConnectionFactory());
187+
}
188+
189+
private JedisConnectionFactory createJedisConnectionFactory() {
190+
if (getSentinelConfig() != null) {
191+
return new JedisConnectionFactory(getSentinelConfig());
192+
}
193+
if (getClusterConfiguration() != null) {
194+
return new JedisConnectionFactory(getClusterConfiguration());
195+
}
196+
return new JedisConnectionFactory();
197+
}
198+
}
199+
200+
/**
201+
* Redis pooled connection configuration.
202+
*/
203+
@Configuration
204+
@ConditionalOnClass(GenericObjectPool.class)
205+
protected static class RedisPooledConnectionConfiguration
206+
extends AbstractRedisConfiguration {
207+
208+
@Bean
209+
@ConditionalOnMissingBean(RedisConnectionFactory.class)
210+
public JedisConnectionFactory redisConnectionFactory()
211+
throws UnknownHostException {
212+
return applyProperties(createJedisConnectionFactory());
213+
}
157214

158215
private JedisConnectionFactory createJedisConnectionFactory() {
159216
JedisPoolConfig poolConfig = this.properties.getPool() != null
@@ -180,6 +237,60 @@ private JedisPoolConfig jedisPoolConfig() {
180237

181238
}
182239

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

spring-boot-dependencies/pom.xml

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -120,6 +120,7 @@
120120
<jtds.version>1.3.1</jtds.version>
121121
<junit.version>4.12</junit.version>
122122
<liquibase.version>3.4.2</liquibase.version>
123+
<lettuce.version>3.4.2.Final</lettuce.version>
123124
<log4j2.version>2.5</log4j2.version>
124125
<logback.version>1.1.7</logback.version>
125126
<lombok.version>1.16.8</lombok.version>
@@ -2287,6 +2288,11 @@
22872288
<artifactId>jedis</artifactId>
22882289
<version>${jedis.version}</version>
22892290
</dependency>
2291+
<dependency>
2292+
<groupId>biz.paluch.redis</groupId>
2293+
<artifactId>lettuce</artifactId>
2294+
<version>${lettuce.version}</version>
2295+
</dependency>
22902296
<dependency>
22912297
<groupId>wsdl4j</groupId>
22922298
<artifactId>wsdl4j</artifactId>

spring-boot-docs/pom.xml

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -613,6 +613,11 @@
613613
<artifactId>jedis</artifactId>
614614
<optional>true</optional>
615615
</dependency>
616+
<dependency>
617+
<groupId>biz.paluch.redis</groupId>
618+
<artifactId>lettuce</artifactId>
619+
<optional>true</optional>
620+
</dependency>
616621
</dependencies>
617622
<profiles>
618623
<profile>

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

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -790,6 +790,8 @@ content into your application; rather pick only the properties that you need.
790790
spring.redis.sentinel.nodes= # Comma-separated list of host:port pairs.
791791
spring.redis.timeout=0 # Connection timeout in milliseconds.
792792
793+
# REDIS LETTUCE DRIVER ({sc-spring-boot-autoconfigure}/data/redis/LettuceRedisProperties.{sc-ext}[LettuceRedisProperties])
794+
spring.redis.lettuce.shutdown-timeout=2000 # Shutdown timeout in milliseconds.
793795
794796
# ----------------------------------------
795797
# INTEGRATION PROPERTIES

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

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2991,3 +2991,44 @@ but the rest of it is normal for a Spring application in Servlet 2.5. Example:
29912991
In this example we are using a single application context (the one created by the context
29922992
listener) and attaching it to the `DispatcherServlet` using an init parameter. This is
29932993
normal in a Spring Boot application (you normally only have one application context).
2994+
2995+
[[howto-use-lettuce-instead-of-jedis]]
2996+
=== Use Lettuce instead of Jedis
2997+
The Spring Boot Redis starter (`spring-boot-starter-data-redis` in particular) uses
2998+
https://github.com/xetorthio/jedis/[Jedis] by default. You need to exclude that dependency
2999+
and include the https://github.com/mp911de/lettuce/[Lettuce] one instead. Spring Boot provides a managed dependency
3000+
to help make this process as easy as possible.
3001+
3002+
Example in Maven:
3003+
3004+
[source,xml,indent=0,subs="verbatim,quotes,attributes"]
3005+
----
3006+
<dependency>
3007+
<groupId>org.springframework.boot</groupId>
3008+
<artifactId>spring-boot-starter-data-redis</artifactId>
3009+
<exclusions>
3010+
<exclusion>
3011+
<groupId>redis.clients</groupId>
3012+
<artifactId>jedis</artifactId>
3013+
</exclusion>
3014+
</exclusions>
3015+
</dependency>
3016+
<dependency>
3017+
<groupId>biz.paluch.redis</groupId>
3018+
<artifactId>lettuce</artifactId>
3019+
</dependency>
3020+
----
3021+
3022+
Example in Gradle:
3023+
3024+
[source,groovy,indent=0,subs="verbatim,quotes,attributes"]
3025+
----
3026+
configurations {
3027+
compile.exclude module: "jedis"
3028+
}
3029+
3030+
dependencies {
3031+
compile("biz.paluch.redis:lettuce:{lettuce.version}")
3032+
// ...
3033+
}
3034+
----

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

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

29112911

29122912

0 commit comments

Comments
 (0)