From 90eb58252e678f6ea37b321e9377ece254fc9473 Mon Sep 17 00:00:00 2001 From: Marco Aust Date: Tue, 15 Nov 2016 19:44:34 +0100 Subject: [PATCH 1/2] Add support for `spring.redis.url` property Update `RedisAutoConfiguration` to optionally configure Redis using a `spring.redis.url` property`. Closes gh-7395 --- .../data/redis/RedisAutoConfiguration.java | 36 ++++++++++++++++--- .../data/redis/RedisProperties.java | 27 ++++++++++++++ .../redis/RedisAutoConfigurationTests.java | 16 +++++++++ .../appendix-application-properties.adoc | 2 ++ 4 files changed, 77 insertions(+), 4 deletions(-) diff --git a/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/data/redis/RedisAutoConfiguration.java b/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/data/redis/RedisAutoConfiguration.java index 618377f889..5a42e7fd81 100644 --- a/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/data/redis/RedisAutoConfiguration.java +++ b/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/data/redis/RedisAutoConfiguration.java @@ -16,10 +16,14 @@ package org.springframework.boot.autoconfigure.data.redis; +import java.net.URI; +import java.net.URISyntaxException; import java.net.UnknownHostException; import java.util.ArrayList; import java.util.List; +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; import org.apache.commons.pool2.impl.GenericObjectPool; import redis.clients.jedis.Jedis; import redis.clients.jedis.JedisPoolConfig; @@ -55,12 +59,15 @@ import org.springframework.util.StringUtils; * @author Phillip Webb * @author Eddú Meléndez * @author Stephane Nicoll + * @author Marco Aust */ @Configuration @ConditionalOnClass({ JedisConnection.class, RedisOperations.class, Jedis.class }) @EnableConfigurationProperties(RedisProperties.class) public class RedisAutoConfiguration { + private static final Log logger = LogFactory.getLog(RedisAutoConfiguration.class); + /** * Redis connection configuration. */ @@ -91,10 +98,31 @@ public class RedisAutoConfiguration { protected final JedisConnectionFactory applyProperties( JedisConnectionFactory factory) { - factory.setHostName(this.properties.getHost()); - factory.setPort(this.properties.getPort()); - if (this.properties.getPassword() != null) { - factory.setPassword(this.properties.getPassword()); + if (StringUtils.hasText(this.properties.getUrl())) { + if (this.properties.getUrl().startsWith("rediss://")) { + factory.setUseSsl(true); + } + try { + URI redisURI = new URI(this.properties.getUrl()); + factory.setHostName(redisURI.getHost()); + factory.setPort(redisURI.getPort()); + if (redisURI.getUserInfo() != null) { + factory.setPassword(redisURI.getUserInfo().split(":", 2)[1]); + } + } + catch (URISyntaxException e) { + logger.error("Incorrect spring.redis.url", e); + } + } + else { + factory.setHostName(this.properties.getHost()); + factory.setPort(this.properties.getPort()); + if (this.properties.getPassword() != null) { + factory.setPassword(this.properties.getPassword()); + } + } + if (this.properties.isSsl()) { + factory.setUseSsl(true); } factory.setDatabase(this.properties.getDatabase()); if (this.properties.getTimeout() > 0) { diff --git a/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/data/redis/RedisProperties.java b/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/data/redis/RedisProperties.java index 8c6d3ddfdf..cd182a485d 100644 --- a/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/data/redis/RedisProperties.java +++ b/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/data/redis/RedisProperties.java @@ -26,6 +26,7 @@ import org.springframework.boot.context.properties.ConfigurationProperties; * @author Dave Syer * @author Christoph Strobl * @author Eddú Meléndez + * @author Marco Aust */ @ConfigurationProperties(prefix = "spring.redis") public class RedisProperties { @@ -35,6 +36,11 @@ public class RedisProperties { */ private int database = 0; + /** + * Redis url, which will overrule host, port and password if set. + */ + private String url; + /** * Redis server host. */ @@ -50,6 +56,11 @@ public class RedisProperties { */ private int port = 6379; + /** + * Enable SSL. + */ + private boolean ssl; + /** * Connection timeout in milliseconds. */ @@ -69,6 +80,14 @@ public class RedisProperties { this.database = database; } + public String getUrl() { + return this.url; + } + + public void setUrl(String url) { + this.url = url; + } + public String getHost() { return this.host; } @@ -93,6 +112,14 @@ public class RedisProperties { this.port = port; } + public boolean isSsl() { + return this.ssl; + } + + public void setSsl(boolean ssl) { + this.ssl = ssl; + } + public void setTimeout(int timeout) { this.timeout = timeout; } diff --git a/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/data/redis/RedisAutoConfigurationTests.java b/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/data/redis/RedisAutoConfigurationTests.java index e75f3e9e85..831e7b2809 100644 --- a/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/data/redis/RedisAutoConfigurationTests.java +++ b/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/data/redis/RedisAutoConfigurationTests.java @@ -75,6 +75,22 @@ public class RedisAutoConfigurationTests { .isEqualTo(1); } + @Test + public void testOverrideURLRedisConfiguration() throws Exception { + load("spring.redis.host:foo", "spring.redis.password:xyz", + "spring.redis.port:1000", + "spring.redis.ssl:true", + "spring.redis.url:redis://user:password@example:33"); + assertThat(this.context.getBean(JedisConnectionFactory.class).getHostName()) + .isEqualTo("example"); + assertThat(this.context.getBean(JedisConnectionFactory.class).getPort()) + .isEqualTo(33); + assertThat(this.context.getBean(JedisConnectionFactory.class).getPassword()) + .isEqualTo("password"); + assertThat(this.context.getBean(JedisConnectionFactory.class).isUseSsl()) + .isEqualTo(true); + } + @Test public void testRedisConfigurationWithPool() throws Exception { load("spring.redis.host:foo", "spring.redis.pool.max-idle:1"); diff --git a/spring-boot-docs/src/main/asciidoc/appendix-application-properties.adoc b/spring-boot-docs/src/main/asciidoc/appendix-application-properties.adoc index 47008f6b67..ab2b8b3220 100644 --- a/spring-boot-docs/src/main/asciidoc/appendix-application-properties.adoc +++ b/spring-boot-docs/src/main/asciidoc/appendix-application-properties.adoc @@ -799,8 +799,10 @@ content into your application; rather pick only the properties that you need. spring.redis.cluster.max-redirects= # Maximum number of redirects to follow when executing commands across the cluster. spring.redis.cluster.nodes= # Comma-separated list of "host:port" pairs to bootstrap from. spring.redis.database=0 # Database index used by the connection factory. + spring.redis.url= # Connection URL, will override host, port and password (user will be ignored), e.g. redis://user:password@example.com:6379 spring.redis.host=localhost # Redis server host. spring.redis.password= # Login password of the redis server. + spring.redis.ssl=false # Enable SSL support. spring.redis.pool.max-active=8 # Max number of connections that can be allocated by the pool at a given time. Use a negative value for no limit. spring.redis.pool.max-idle=8 # Max number of "idle" connections in the pool. Use a negative value to indicate an unlimited number of idle connections. spring.redis.pool.max-wait=-1 # Maximum amount of time (in milliseconds) a connection allocation should block before throwing an exception when the pool is exhausted. Use a negative value to block indefinitely. From 8f7efbe12a9ee1a564b4a1959b057e1d92430105 Mon Sep 17 00:00:00 2001 From: Phillip Webb Date: Tue, 20 Dec 2016 20:57:50 -0800 Subject: [PATCH 2/2] Polish `spring.redis.url` support See gh-7395 --- .../data/redis/RedisAutoConfiguration.java | 65 +++++++++++-------- .../redis/RedisAutoConfigurationTests.java | 6 +- 2 files changed, 41 insertions(+), 30 deletions(-) diff --git a/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/data/redis/RedisAutoConfiguration.java b/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/data/redis/RedisAutoConfiguration.java index 5a42e7fd81..1c770888d5 100644 --- a/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/data/redis/RedisAutoConfiguration.java +++ b/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/data/redis/RedisAutoConfiguration.java @@ -22,8 +22,6 @@ import java.net.UnknownHostException; import java.util.ArrayList; import java.util.List; -import org.apache.commons.logging.Log; -import org.apache.commons.logging.LogFactory; import org.apache.commons.pool2.impl.GenericObjectPool; import redis.clients.jedis.Jedis; import redis.clients.jedis.JedisPoolConfig; @@ -66,8 +64,6 @@ import org.springframework.util.StringUtils; @EnableConfigurationProperties(RedisProperties.class) public class RedisAutoConfiguration { - private static final Log logger = LogFactory.getLog(RedisAutoConfiguration.class); - /** * Redis connection configuration. */ @@ -98,29 +94,7 @@ public class RedisAutoConfiguration { protected final JedisConnectionFactory applyProperties( JedisConnectionFactory factory) { - if (StringUtils.hasText(this.properties.getUrl())) { - if (this.properties.getUrl().startsWith("rediss://")) { - factory.setUseSsl(true); - } - try { - URI redisURI = new URI(this.properties.getUrl()); - factory.setHostName(redisURI.getHost()); - factory.setPort(redisURI.getPort()); - if (redisURI.getUserInfo() != null) { - factory.setPassword(redisURI.getUserInfo().split(":", 2)[1]); - } - } - catch (URISyntaxException e) { - logger.error("Incorrect spring.redis.url", e); - } - } - else { - factory.setHostName(this.properties.getHost()); - factory.setPort(this.properties.getPort()); - if (this.properties.getPassword() != null) { - factory.setPassword(this.properties.getPassword()); - } - } + configureConnection(factory); if (this.properties.isSsl()) { factory.setUseSsl(true); } @@ -131,6 +105,43 @@ public class RedisAutoConfiguration { return factory; } + private void configureConnection(JedisConnectionFactory factory) { + if (StringUtils.hasText(this.properties.getUrl())) { + configureConnectionFromUrl(factory); + } + else { + factory.setHostName(this.properties.getHost()); + factory.setPort(this.properties.getPort()); + if (this.properties.getPassword() != null) { + factory.setPassword(this.properties.getPassword()); + } + } + } + + private void configureConnectionFromUrl(JedisConnectionFactory factory) { + String url = this.properties.getUrl(); + if (url.startsWith("rediss://")) { + factory.setUseSsl(true); + } + try { + URI uri = new URI(url); + factory.setHostName(uri.getHost()); + factory.setPort(uri.getPort()); + if (uri.getUserInfo() != null) { + String password = uri.getUserInfo(); + int index = password.lastIndexOf(":"); + if (index >= 0) { + password = password.substring(index + 1); + } + factory.setPassword(password); + } + } + catch (URISyntaxException ex) { + throw new IllegalArgumentException("Malformed 'spring.redis.url' " + url, + ex); + } + } + protected final RedisSentinelConfiguration getSentinelConfig() { if (this.sentinelConfiguration != null) { return this.sentinelConfiguration; diff --git a/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/data/redis/RedisAutoConfigurationTests.java b/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/data/redis/RedisAutoConfigurationTests.java index 831e7b2809..69be81f6dc 100644 --- a/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/data/redis/RedisAutoConfigurationTests.java +++ b/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/data/redis/RedisAutoConfigurationTests.java @@ -41,6 +41,7 @@ import static org.assertj.core.api.Assertions.assertThat; * @author Christian Dupuis * @author Christoph Strobl * @author Eddú Meléndez + * @author Marco Aust */ public class RedisAutoConfigurationTests { @@ -76,10 +77,9 @@ public class RedisAutoConfigurationTests { } @Test - public void testOverrideURLRedisConfiguration() throws Exception { + public void testOverrideUrlRedisConfiguration() throws Exception { load("spring.redis.host:foo", "spring.redis.password:xyz", - "spring.redis.port:1000", - "spring.redis.ssl:true", + "spring.redis.port:1000", "spring.redis.ssl:true", "spring.redis.url:redis://user:password@example:33"); assertThat(this.context.getBean(JedisConnectionFactory.class).getHostName()) .isEqualTo("example");