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..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 @@ -16,6 +16,8 @@ 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; @@ -55,6 +57,7 @@ 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 }) @@ -91,10 +94,9 @@ 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()); + configureConnection(factory); + if (this.properties.isSsl()) { + factory.setUseSsl(true); } factory.setDatabase(this.properties.getDatabase()); if (this.properties.getTimeout() > 0) { @@ -103,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/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..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 { @@ -75,6 +76,21 @@ 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.