From 283c9de28fd6cbde5e7e7e83631f1e4327bd4453 Mon Sep 17 00:00:00 2001 From: Ryon Date: Mon, 6 Nov 2017 13:51:03 -0600 Subject: [PATCH 1/4] Improve spring-boot-autoconfigure for Redis caches Expose key prefix, TTL and null value settings for spring-data-redis' RedisCacheConfiguration in Spring .properties/yml configuration files. Example: spring.cache.redis.ttl=PT15M spring.cache.redis.keyPrefix=foo spring.cache.redis.useKeyPrefix=false spring.cache.redis.cacheNullValues=false Fixes gs-10795 --- .../autoconfigure/cache/CacheProperties.java | 77 +++++++++++++++++++ .../cache/RedisCacheConfiguration.java | 29 ++++++- .../cache/CacheAutoConfigurationTests.java | 31 ++++++-- 3 files changed, 131 insertions(+), 6 deletions(-) diff --git a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/cache/CacheProperties.java b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/cache/CacheProperties.java index 1d299e70e6..6fe5a6d0b0 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/cache/CacheProperties.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/cache/CacheProperties.java @@ -16,8 +16,10 @@ package org.springframework.boot.autoconfigure.cache; +import java.time.Duration; import java.util.ArrayList; import java.util.List; +import java.util.Optional; import java.util.concurrent.TimeUnit; import org.springframework.boot.context.properties.ConfigurationProperties; @@ -29,6 +31,7 @@ import org.springframework.util.Assert; * * @author Stephane Nicoll * @author Eddú Meléndez + * @author Ryon Day * @since 1.3.0 */ @ConfigurationProperties(prefix = "spring.cache") @@ -55,6 +58,8 @@ public class CacheProperties { private final JCache jcache = new JCache(); + private final Redis redis = new Redis(); + public CacheType getType() { return this.type; } @@ -91,6 +96,10 @@ public class CacheProperties { return this.jcache; } + public Redis getRedis() { + return this.redis; + } + /** * Resolve the config location if set. * @param config the config resource @@ -233,4 +242,72 @@ public class CacheProperties { } + /** + * Redis-specific cache properties. Properties set will be used as the defaults for + * all Redis caches. + * + * @see org.springframework.data.redis.cache.RedisCacheConfiguration + */ + public static class Redis { + + /** + * The TTL for entries. By default, entries do not expire, a value of zero + * indicates an eternal entry, and the given value will be converted to seconds.. + * + * @see Duration#parse(CharSequence) + */ + private Duration ttl = Duration.ZERO; + + /** + * Whether to allow caching of {@literal null} values. + */ + private boolean cacheNullValues = true; + + /** + * The non-null Redis key prefix to use instead of the default one. + */ + private String keyPrefix; + + /** + * Whether to use the key prefix when writing to Redis. + */ + private boolean useKeyPrefix = true; + + public Duration getTtl() { + return this.ttl; + } + + public Redis setTtl(Duration ttl) { + this.ttl = ttl; + return this; + } + + public boolean isCacheNullValues() { + return this.cacheNullValues; + } + + public Redis setCacheNullValues(boolean cacheNullValues) { + this.cacheNullValues = cacheNullValues; + return this; + } + + public Optional getKeyPrefix() { + return Optional.ofNullable(this.keyPrefix); + } + + public Redis setKeyPrefix(String keyPrefix) { + this.keyPrefix = keyPrefix; + return this; + } + + public boolean isUseKeyPrefix() { + return this.useKeyPrefix; + } + + public Redis setUseKeyPrefix(boolean useKeyPrefix) { + this.useKeyPrefix = useKeyPrefix; + return this; + } + } + } diff --git a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/cache/RedisCacheConfiguration.java b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/cache/RedisCacheConfiguration.java index ce6e0e2587..d8fa90b192 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/cache/RedisCacheConfiguration.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/cache/RedisCacheConfiguration.java @@ -20,6 +20,7 @@ import java.util.LinkedHashSet; import java.util.List; import org.springframework.boot.autoconfigure.AutoConfigureAfter; +import org.springframework.boot.autoconfigure.cache.CacheProperties.Redis; import org.springframework.boot.autoconfigure.condition.ConditionalOnBean; import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; import org.springframework.boot.autoconfigure.data.redis.RedisAutoConfiguration; @@ -36,6 +37,7 @@ import org.springframework.data.redis.connection.RedisConnectionFactory; * * @author Stephane Nicoll * @author Mark Paluch + * @author Ryon Day * @since 1.3.0 */ @Configuration @@ -57,13 +59,38 @@ class RedisCacheConfiguration { @Bean public RedisCacheManager cacheManager(RedisConnectionFactory redisConnectionFactory) { + RedisCacheManagerBuilder builder = RedisCacheManager - .builder(redisConnectionFactory); + .builder(redisConnectionFactory).cacheDefaults(getConfiguration()); + List cacheNames = this.cacheProperties.getCacheNames(); if (!cacheNames.isEmpty()) { builder.initialCacheNames(new LinkedHashSet<>(cacheNames)); } + return this.customizerInvoker.customize(builder.build()); } + private org.springframework.data.redis.cache.RedisCacheConfiguration getConfiguration() { + + Redis redisProperties = this.cacheProperties.getRedis(); + + org.springframework.data.redis.cache.RedisCacheConfiguration config = org.springframework.data.redis.cache.RedisCacheConfiguration + .defaultCacheConfig().entryTtl(redisProperties.getTtl()); + + if (redisProperties.getKeyPrefix().isPresent()) { + config = config.prefixKeysWith(redisProperties.getKeyPrefix().get()); + } + + if (!redisProperties.isCacheNullValues()) { + config = config.disableCachingNullValues(); + } + + if (!redisProperties.isUseKeyPrefix()) { + config = config.disableKeyPrefix(); + } + + return config; + } + } diff --git a/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/cache/CacheAutoConfigurationTests.java b/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/cache/CacheAutoConfigurationTests.java index 9019e77c24..f3342fad5c 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/cache/CacheAutoConfigurationTests.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/cache/CacheAutoConfigurationTests.java @@ -90,6 +90,7 @@ import static org.mockito.Mockito.verify; * @author Stephane Nicoll * @author Eddú Meléndez * @author Mark Paluch + * @author Ryon Day */ @RunWith(ModifiedClassPathRunner.class) @ClassPathExclusions("hazelcast-client-*.jar") @@ -280,14 +281,25 @@ public class CacheAutoConfigurationTests { @Test public void redisCacheExplicit() { this.contextRunner.withUserConfiguration(RedisCacheConfiguration.class) - .withPropertyValues("spring.cache.type=redis").run((context) -> { + .withPropertyValues("spring.cache.type=redis", + "spring.cache.redis.ttl=PT15M", + "spring.cache.redis.keyPrefix=foo", + "spring.cache.redis.useKeyPrefix=false", + "spring.cache.redis.cacheNullValues=false") + .run((context) -> { RedisCacheManager cacheManager = getCacheManager(context, RedisCacheManager.class); assertThat(cacheManager.getCacheNames()).isEmpty(); - assertThat( - ((org.springframework.data.redis.cache.RedisCacheConfiguration) new DirectFieldAccessor( - cacheManager).getPropertyValue("defaultCacheConfig")) - .usePrefix()).isTrue(); + + org.springframework.data.redis.cache.RedisCacheConfiguration redisCacheConfiguration = (org.springframework.data.redis.cache.RedisCacheConfiguration) new DirectFieldAccessor( + cacheManager).getPropertyValue("defaultCacheConfig"); + + assertThat(redisCacheConfiguration.usePrefix()).isFalse(); + assertThat(redisCacheConfiguration.getKeyPrefix()).contains("foo"); + assertThat(redisCacheConfiguration.getTtl()) + .isEqualTo(java.time.Duration.ofMinutes(15)); + assertThat(redisCacheConfiguration.getAllowCacheNullValues()) + .isFalse(); }); } @@ -309,6 +321,15 @@ public class CacheAutoConfigurationTests { RedisCacheManager cacheManager = getCacheManager(context, RedisCacheManager.class); assertThat(cacheManager.getCacheNames()).containsOnly("foo", "bar"); + + org.springframework.data.redis.cache.RedisCacheConfiguration redisCacheConfiguration = (org.springframework.data.redis.cache.RedisCacheConfiguration) new DirectFieldAccessor( + cacheManager).getPropertyValue("defaultCacheConfig"); + assertThat(redisCacheConfiguration.usePrefix()).isTrue(); + assertThat(redisCacheConfiguration.getKeyPrefix()).isEmpty(); + assertThat(redisCacheConfiguration.getTtl()) + .isEqualTo(java.time.Duration.ofMinutes(0)); + assertThat(redisCacheConfiguration.getAllowCacheNullValues()) + .isTrue(); }); } From 1ba646965c3b6cafe6ab5c969064ac0025ac6bc6 Mon Sep 17 00:00:00 2001 From: Ryon Date: Tue, 7 Nov 2017 10:32:28 -0600 Subject: [PATCH 2/4] Respond to MR feedback * Remove unnecessary formatting changes * Discontinue use of Optional for Redis property configuration * Remove @see tags * Change verbiage for property descriptions Fixes gs-10795 --- .../autoconfigure/cache/CacheProperties.java | 16 ++++++---------- .../cache/RedisCacheConfiguration.java | 7 ++----- 2 files changed, 8 insertions(+), 15 deletions(-) diff --git a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/cache/CacheProperties.java b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/cache/CacheProperties.java index 6fe5a6d0b0..a0b87e3c1e 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/cache/CacheProperties.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/cache/CacheProperties.java @@ -19,7 +19,6 @@ package org.springframework.boot.autoconfigure.cache; import java.time.Duration; import java.util.ArrayList; import java.util.List; -import java.util.Optional; import java.util.concurrent.TimeUnit; import org.springframework.boot.context.properties.ConfigurationProperties; @@ -245,16 +244,12 @@ public class CacheProperties { /** * Redis-specific cache properties. Properties set will be used as the defaults for * all Redis caches. - * - * @see org.springframework.data.redis.cache.RedisCacheConfiguration */ public static class Redis { /** - * The TTL for entries. By default, entries do not expire, a value of zero - * indicates an eternal entry, and the given value will be converted to seconds.. - * - * @see Duration#parse(CharSequence) + * Specifies the TTL (ultimately converted to seconds) for keys written to Redis. + * By default, entries do not expire, and a value of {@link Duration#ZERO} disables the TTL. */ private Duration ttl = Duration.ZERO; @@ -264,7 +259,8 @@ public class CacheProperties { private boolean cacheNullValues = true; /** - * The non-null Redis key prefix to use instead of the default one. + * Specifies an override for the default Redis key prefix. A value of {@literal null} results + * in usage of the default key prefix. */ private String keyPrefix; @@ -291,8 +287,8 @@ public class CacheProperties { return this; } - public Optional getKeyPrefix() { - return Optional.ofNullable(this.keyPrefix); + public String getKeyPrefix() { + return this.keyPrefix; } public Redis setKeyPrefix(String keyPrefix) { diff --git a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/cache/RedisCacheConfiguration.java b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/cache/RedisCacheConfiguration.java index d8fa90b192..057a94313b 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/cache/RedisCacheConfiguration.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/cache/RedisCacheConfiguration.java @@ -59,15 +59,12 @@ class RedisCacheConfiguration { @Bean public RedisCacheManager cacheManager(RedisConnectionFactory redisConnectionFactory) { - RedisCacheManagerBuilder builder = RedisCacheManager .builder(redisConnectionFactory).cacheDefaults(getConfiguration()); - List cacheNames = this.cacheProperties.getCacheNames(); if (!cacheNames.isEmpty()) { builder.initialCacheNames(new LinkedHashSet<>(cacheNames)); } - return this.customizerInvoker.customize(builder.build()); } @@ -78,8 +75,8 @@ class RedisCacheConfiguration { org.springframework.data.redis.cache.RedisCacheConfiguration config = org.springframework.data.redis.cache.RedisCacheConfiguration .defaultCacheConfig().entryTtl(redisProperties.getTtl()); - if (redisProperties.getKeyPrefix().isPresent()) { - config = config.prefixKeysWith(redisProperties.getKeyPrefix().get()); + if (redisProperties.getKeyPrefix() != null) { + config = config.prefixKeysWith(redisProperties.getKeyPrefix()); } if (!redisProperties.isCacheNullValues()) { From a4ed406ee8b935f33b6fe36b2d6ee6ecf5349b8f Mon Sep 17 00:00:00 2001 From: Ryon Date: Mon, 6 Nov 2017 13:51:03 -0600 Subject: [PATCH 3/4] Improve cache auto-configuration for Redis Expose key prefix, TTL and null value settings for spring-data-redis' RedisCacheConfiguration in Spring .properties/yml configuration files. Example: spring.cache.redis.ttl=PT15M spring.cache.redis.keyPrefix=foo spring.cache.redis.useKeyPrefix=false spring.cache.redis.cacheNullValues=false See gh-10795 --- .../autoconfigure/cache/CacheProperties.java | 73 +++++++++++++++++++ .../cache/RedisCacheConfiguration.java | 26 ++++++- .../cache/CacheAutoConfigurationTests.java | 31 ++++++-- 3 files changed, 124 insertions(+), 6 deletions(-) diff --git a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/cache/CacheProperties.java b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/cache/CacheProperties.java index 1d299e70e6..a0b87e3c1e 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/cache/CacheProperties.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/cache/CacheProperties.java @@ -16,6 +16,7 @@ package org.springframework.boot.autoconfigure.cache; +import java.time.Duration; import java.util.ArrayList; import java.util.List; import java.util.concurrent.TimeUnit; @@ -29,6 +30,7 @@ import org.springframework.util.Assert; * * @author Stephane Nicoll * @author Eddú Meléndez + * @author Ryon Day * @since 1.3.0 */ @ConfigurationProperties(prefix = "spring.cache") @@ -55,6 +57,8 @@ public class CacheProperties { private final JCache jcache = new JCache(); + private final Redis redis = new Redis(); + public CacheType getType() { return this.type; } @@ -91,6 +95,10 @@ public class CacheProperties { return this.jcache; } + public Redis getRedis() { + return this.redis; + } + /** * Resolve the config location if set. * @param config the config resource @@ -233,4 +241,69 @@ public class CacheProperties { } + /** + * Redis-specific cache properties. Properties set will be used as the defaults for + * all Redis caches. + */ + public static class Redis { + + /** + * Specifies the TTL (ultimately converted to seconds) for keys written to Redis. + * By default, entries do not expire, and a value of {@link Duration#ZERO} disables the TTL. + */ + private Duration ttl = Duration.ZERO; + + /** + * Whether to allow caching of {@literal null} values. + */ + private boolean cacheNullValues = true; + + /** + * Specifies an override for the default Redis key prefix. A value of {@literal null} results + * in usage of the default key prefix. + */ + private String keyPrefix; + + /** + * Whether to use the key prefix when writing to Redis. + */ + private boolean useKeyPrefix = true; + + public Duration getTtl() { + return this.ttl; + } + + public Redis setTtl(Duration ttl) { + this.ttl = ttl; + return this; + } + + public boolean isCacheNullValues() { + return this.cacheNullValues; + } + + public Redis setCacheNullValues(boolean cacheNullValues) { + this.cacheNullValues = cacheNullValues; + return this; + } + + public String getKeyPrefix() { + return this.keyPrefix; + } + + public Redis setKeyPrefix(String keyPrefix) { + this.keyPrefix = keyPrefix; + return this; + } + + public boolean isUseKeyPrefix() { + return this.useKeyPrefix; + } + + public Redis setUseKeyPrefix(boolean useKeyPrefix) { + this.useKeyPrefix = useKeyPrefix; + return this; + } + } + } diff --git a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/cache/RedisCacheConfiguration.java b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/cache/RedisCacheConfiguration.java index ce6e0e2587..057a94313b 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/cache/RedisCacheConfiguration.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/cache/RedisCacheConfiguration.java @@ -20,6 +20,7 @@ import java.util.LinkedHashSet; import java.util.List; import org.springframework.boot.autoconfigure.AutoConfigureAfter; +import org.springframework.boot.autoconfigure.cache.CacheProperties.Redis; import org.springframework.boot.autoconfigure.condition.ConditionalOnBean; import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; import org.springframework.boot.autoconfigure.data.redis.RedisAutoConfiguration; @@ -36,6 +37,7 @@ import org.springframework.data.redis.connection.RedisConnectionFactory; * * @author Stephane Nicoll * @author Mark Paluch + * @author Ryon Day * @since 1.3.0 */ @Configuration @@ -58,7 +60,7 @@ class RedisCacheConfiguration { @Bean public RedisCacheManager cacheManager(RedisConnectionFactory redisConnectionFactory) { RedisCacheManagerBuilder builder = RedisCacheManager - .builder(redisConnectionFactory); + .builder(redisConnectionFactory).cacheDefaults(getConfiguration()); List cacheNames = this.cacheProperties.getCacheNames(); if (!cacheNames.isEmpty()) { builder.initialCacheNames(new LinkedHashSet<>(cacheNames)); @@ -66,4 +68,26 @@ class RedisCacheConfiguration { return this.customizerInvoker.customize(builder.build()); } + private org.springframework.data.redis.cache.RedisCacheConfiguration getConfiguration() { + + Redis redisProperties = this.cacheProperties.getRedis(); + + org.springframework.data.redis.cache.RedisCacheConfiguration config = org.springframework.data.redis.cache.RedisCacheConfiguration + .defaultCacheConfig().entryTtl(redisProperties.getTtl()); + + if (redisProperties.getKeyPrefix() != null) { + config = config.prefixKeysWith(redisProperties.getKeyPrefix()); + } + + if (!redisProperties.isCacheNullValues()) { + config = config.disableCachingNullValues(); + } + + if (!redisProperties.isUseKeyPrefix()) { + config = config.disableKeyPrefix(); + } + + return config; + } + } diff --git a/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/cache/CacheAutoConfigurationTests.java b/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/cache/CacheAutoConfigurationTests.java index 9019e77c24..f3342fad5c 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/cache/CacheAutoConfigurationTests.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/cache/CacheAutoConfigurationTests.java @@ -90,6 +90,7 @@ import static org.mockito.Mockito.verify; * @author Stephane Nicoll * @author Eddú Meléndez * @author Mark Paluch + * @author Ryon Day */ @RunWith(ModifiedClassPathRunner.class) @ClassPathExclusions("hazelcast-client-*.jar") @@ -280,14 +281,25 @@ public class CacheAutoConfigurationTests { @Test public void redisCacheExplicit() { this.contextRunner.withUserConfiguration(RedisCacheConfiguration.class) - .withPropertyValues("spring.cache.type=redis").run((context) -> { + .withPropertyValues("spring.cache.type=redis", + "spring.cache.redis.ttl=PT15M", + "spring.cache.redis.keyPrefix=foo", + "spring.cache.redis.useKeyPrefix=false", + "spring.cache.redis.cacheNullValues=false") + .run((context) -> { RedisCacheManager cacheManager = getCacheManager(context, RedisCacheManager.class); assertThat(cacheManager.getCacheNames()).isEmpty(); - assertThat( - ((org.springframework.data.redis.cache.RedisCacheConfiguration) new DirectFieldAccessor( - cacheManager).getPropertyValue("defaultCacheConfig")) - .usePrefix()).isTrue(); + + org.springframework.data.redis.cache.RedisCacheConfiguration redisCacheConfiguration = (org.springframework.data.redis.cache.RedisCacheConfiguration) new DirectFieldAccessor( + cacheManager).getPropertyValue("defaultCacheConfig"); + + assertThat(redisCacheConfiguration.usePrefix()).isFalse(); + assertThat(redisCacheConfiguration.getKeyPrefix()).contains("foo"); + assertThat(redisCacheConfiguration.getTtl()) + .isEqualTo(java.time.Duration.ofMinutes(15)); + assertThat(redisCacheConfiguration.getAllowCacheNullValues()) + .isFalse(); }); } @@ -309,6 +321,15 @@ public class CacheAutoConfigurationTests { RedisCacheManager cacheManager = getCacheManager(context, RedisCacheManager.class); assertThat(cacheManager.getCacheNames()).containsOnly("foo", "bar"); + + org.springframework.data.redis.cache.RedisCacheConfiguration redisCacheConfiguration = (org.springframework.data.redis.cache.RedisCacheConfiguration) new DirectFieldAccessor( + cacheManager).getPropertyValue("defaultCacheConfig"); + assertThat(redisCacheConfiguration.usePrefix()).isTrue(); + assertThat(redisCacheConfiguration.getKeyPrefix()).isEmpty(); + assertThat(redisCacheConfiguration.getTtl()) + .isEqualTo(java.time.Duration.ofMinutes(0)); + assertThat(redisCacheConfiguration.getAllowCacheNullValues()) + .isTrue(); }); } From 46ef178f0407e71421a34f68829904a8ec9da840 Mon Sep 17 00:00:00 2001 From: Stephane Nicoll Date: Fri, 10 Nov 2017 14:42:50 +0100 Subject: [PATCH 4/4] Polish "Improve cache auto-configuration for Redis" Closes gh-10944 --- .../autoconfigure/cache/CacheProperties.java | 33 ++++++++----------- .../cache/RedisCacheConfiguration.java | 10 ++---- .../cache/CacheAutoConfigurationTests.java | 19 +++++------ .../appendix-application-properties.adoc | 4 +++ .../main/asciidoc/spring-boot-features.adoc | 14 ++++++-- 5 files changed, 39 insertions(+), 41 deletions(-) diff --git a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/cache/CacheProperties.java b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/cache/CacheProperties.java index a0b87e3c1e..231a2f9ff3 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/cache/CacheProperties.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/cache/CacheProperties.java @@ -16,7 +16,6 @@ package org.springframework.boot.autoconfigure.cache; -import java.time.Duration; import java.util.ArrayList; import java.util.List; import java.util.concurrent.TimeUnit; @@ -242,25 +241,22 @@ public class CacheProperties { } /** - * Redis-specific cache properties. Properties set will be used as the defaults for - * all Redis caches. + * Redis-specific cache properties. */ public static class Redis { /** - * Specifies the TTL (ultimately converted to seconds) for keys written to Redis. - * By default, entries do not expire, and a value of {@link Duration#ZERO} disables the TTL. + * Entry expiration in milliseconds. By default the entries never expire. */ - private Duration ttl = Duration.ZERO; + private long timeToLive = 0; /** - * Whether to allow caching of {@literal null} values. + * Allow caching null values. */ private boolean cacheNullValues = true; /** - * Specifies an override for the default Redis key prefix. A value of {@literal null} results - * in usage of the default key prefix. + * Key prefix. */ private String keyPrefix; @@ -269,41 +265,38 @@ public class CacheProperties { */ private boolean useKeyPrefix = true; - public Duration getTtl() { - return this.ttl; + public long getTimeToLive() { + return this.timeToLive; } - public Redis setTtl(Duration ttl) { - this.ttl = ttl; - return this; + public void setTimeToLive(long timeToLive) { + this.timeToLive = timeToLive; } public boolean isCacheNullValues() { return this.cacheNullValues; } - public Redis setCacheNullValues(boolean cacheNullValues) { + public void setCacheNullValues(boolean cacheNullValues) { this.cacheNullValues = cacheNullValues; - return this; } public String getKeyPrefix() { return this.keyPrefix; } - public Redis setKeyPrefix(String keyPrefix) { + public void setKeyPrefix(String keyPrefix) { this.keyPrefix = keyPrefix; - return this; } public boolean isUseKeyPrefix() { return this.useKeyPrefix; } - public Redis setUseKeyPrefix(boolean useKeyPrefix) { + public void setUseKeyPrefix(boolean useKeyPrefix) { this.useKeyPrefix = useKeyPrefix; - return this; } + } } diff --git a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/cache/RedisCacheConfiguration.java b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/cache/RedisCacheConfiguration.java index 057a94313b..4cf3ce8133 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/cache/RedisCacheConfiguration.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/cache/RedisCacheConfiguration.java @@ -16,6 +16,7 @@ package org.springframework.boot.autoconfigure.cache; +import java.time.Duration; import java.util.LinkedHashSet; import java.util.List; @@ -69,24 +70,19 @@ class RedisCacheConfiguration { } private org.springframework.data.redis.cache.RedisCacheConfiguration getConfiguration() { - Redis redisProperties = this.cacheProperties.getRedis(); - org.springframework.data.redis.cache.RedisCacheConfiguration config = org.springframework.data.redis.cache.RedisCacheConfiguration - .defaultCacheConfig().entryTtl(redisProperties.getTtl()); - + .defaultCacheConfig(); + config = config.entryTtl(Duration.ofMillis(redisProperties.getTimeToLive())); if (redisProperties.getKeyPrefix() != null) { config = config.prefixKeysWith(redisProperties.getKeyPrefix()); } - if (!redisProperties.isCacheNullValues()) { config = config.disableCachingNullValues(); } - if (!redisProperties.isUseKeyPrefix()) { config = config.disableKeyPrefix(); } - return config; } diff --git a/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/cache/CacheAutoConfigurationTests.java b/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/cache/CacheAutoConfigurationTests.java index f3342fad5c..302eabf665 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/cache/CacheAutoConfigurationTests.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/cache/CacheAutoConfigurationTests.java @@ -282,24 +282,22 @@ public class CacheAutoConfigurationTests { public void redisCacheExplicit() { this.contextRunner.withUserConfiguration(RedisCacheConfiguration.class) .withPropertyValues("spring.cache.type=redis", - "spring.cache.redis.ttl=PT15M", + "spring.cache.redis.time-to-live=15000", + "spring.cache.redis.cacheNullValues=false", "spring.cache.redis.keyPrefix=foo", - "spring.cache.redis.useKeyPrefix=false", - "spring.cache.redis.cacheNullValues=false") + "spring.cache.redis.useKeyPrefix=false") .run((context) -> { RedisCacheManager cacheManager = getCacheManager(context, RedisCacheManager.class); assertThat(cacheManager.getCacheNames()).isEmpty(); - org.springframework.data.redis.cache.RedisCacheConfiguration redisCacheConfiguration = (org.springframework.data.redis.cache.RedisCacheConfiguration) new DirectFieldAccessor( cacheManager).getPropertyValue("defaultCacheConfig"); - - assertThat(redisCacheConfiguration.usePrefix()).isFalse(); - assertThat(redisCacheConfiguration.getKeyPrefix()).contains("foo"); assertThat(redisCacheConfiguration.getTtl()) - .isEqualTo(java.time.Duration.ofMinutes(15)); + .isEqualTo(java.time.Duration.ofSeconds(15)); assertThat(redisCacheConfiguration.getAllowCacheNullValues()) .isFalse(); + assertThat(redisCacheConfiguration.getKeyPrefix()).contains("foo"); + assertThat(redisCacheConfiguration.usePrefix()).isFalse(); }); } @@ -321,15 +319,14 @@ public class CacheAutoConfigurationTests { RedisCacheManager cacheManager = getCacheManager(context, RedisCacheManager.class); assertThat(cacheManager.getCacheNames()).containsOnly("foo", "bar"); - org.springframework.data.redis.cache.RedisCacheConfiguration redisCacheConfiguration = (org.springframework.data.redis.cache.RedisCacheConfiguration) new DirectFieldAccessor( cacheManager).getPropertyValue("defaultCacheConfig"); - assertThat(redisCacheConfiguration.usePrefix()).isTrue(); - assertThat(redisCacheConfiguration.getKeyPrefix()).isEmpty(); assertThat(redisCacheConfiguration.getTtl()) .isEqualTo(java.time.Duration.ofMinutes(0)); assertThat(redisCacheConfiguration.getAllowCacheNullValues()) .isTrue(); + assertThat(redisCacheConfiguration.getKeyPrefix()).isEmpty(); + assertThat(redisCacheConfiguration.usePrefix()).isTrue(); }); } diff --git a/spring-boot-project/spring-boot-docs/src/main/asciidoc/appendix-application-properties.adoc b/spring-boot-project/spring-boot-docs/src/main/asciidoc/appendix-application-properties.adoc index c44ca24d4a..c8890b382f 100644 --- a/spring-boot-project/spring-boot-docs/src/main/asciidoc/appendix-application-properties.adoc +++ b/spring-boot-project/spring-boot-docs/src/main/asciidoc/appendix-application-properties.adoc @@ -77,6 +77,10 @@ content into your application; rather pick only the properties that you need. spring.cache.infinispan.config= # The location of the configuration file to use to initialize Infinispan. spring.cache.jcache.config= # The location of the configuration file to use to initialize the cache manager. spring.cache.jcache.provider= # Fully qualified name of the CachingProvider implementation to use to retrieve the JSR-107 compliant cache manager. Only needed if more than one JSR-107 implementation is available on the classpath. + spring.cache.redis.cache-null-values=true # Allow caching null values. + spring.cache.redis.key-prefix= # Key prefix. + spring.cache.redis.time-to-live=0 # Entry expiration in milliseconds. By default the entries never expire. + spring.cache.redis.use-key-prefix=true # Whether to use the key prefix when writing to Redis. spring.cache.type= # Cache type, auto-detected according to the environment by default. # SPRING CONFIG - using environment property only ({sc-spring-boot}/context/config/ConfigFileApplicationListener.{sc-ext}[ConfigFileApplicationListener]) diff --git a/spring-boot-project/spring-boot-docs/src/main/asciidoc/spring-boot-features.adoc b/spring-boot-project/spring-boot-docs/src/main/asciidoc/spring-boot-features.adoc index 6b5942dffa..725b8c1148 100644 --- a/spring-boot-project/spring-boot-docs/src/main/asciidoc/spring-boot-features.adoc +++ b/spring-boot-project/spring-boot-docs/src/main/asciidoc/spring-boot-features.adoc @@ -4546,9 +4546,17 @@ This sample configuration reuses the `Cluster` that was created via auto-configu [[boot-features-caching-provider-redis]] ==== Redis -If Redis is available and configured, the `RedisCacheManager` is auto-configured. It is -also possible to create additional caches on startup by setting the -`spring.cache.cache-names` property. +If Redis is available and configured, a `RedisCacheManager` is auto-configured. It is +possible to create additional caches on startup by setting the +`spring.cache.cache-names` property and cache defaults can be configured using +`spring.redis.cache.*` properties. For instance, the following configuration creates +`cache1` and `cache2` caches with a _time to live_ of 10 minutes: + +[source,properties,indent=0] +---- + spring.cache.cache-names=cache1,cache2 + spring.cache.redis.time-to-live=600000 +---- [NOTE] ====