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..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 @@ -29,6 +29,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 +56,8 @@ public class CacheProperties { private final JCache jcache = new JCache(); + private final Redis redis = new Redis(); + public CacheType getType() { return this.type; } @@ -91,6 +94,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 +240,63 @@ public class CacheProperties { } + /** + * Redis-specific cache properties. + */ + public static class Redis { + + /** + * Entry expiration in milliseconds. By default the entries never expire. + */ + private long timeToLive = 0; + + /** + * Allow caching null values. + */ + private boolean cacheNullValues = true; + + /** + * Key prefix. + */ + private String keyPrefix; + + /** + * Whether to use the key prefix when writing to Redis. + */ + private boolean useKeyPrefix = true; + + public long getTimeToLive() { + return this.timeToLive; + } + + public void setTimeToLive(long timeToLive) { + this.timeToLive = timeToLive; + } + + public boolean isCacheNullValues() { + return this.cacheNullValues; + } + + public void setCacheNullValues(boolean cacheNullValues) { + this.cacheNullValues = cacheNullValues; + } + + public String getKeyPrefix() { + return this.keyPrefix; + } + + public void setKeyPrefix(String keyPrefix) { + this.keyPrefix = keyPrefix; + } + + public boolean isUseKeyPrefix() { + return this.useKeyPrefix; + } + + public void setUseKeyPrefix(boolean useKeyPrefix) { + this.useKeyPrefix = useKeyPrefix; + } + + } + } 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..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,10 +16,12 @@ package org.springframework.boot.autoconfigure.cache; +import java.time.Duration; 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 +38,7 @@ import org.springframework.data.redis.connection.RedisConnectionFactory; * * @author Stephane Nicoll * @author Mark Paluch + * @author Ryon Day * @since 1.3.0 */ @Configuration @@ -58,7 +61,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 +69,21 @@ 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(); + 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 9019e77c24..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 @@ -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,23 @@ 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.time-to-live=15000", + "spring.cache.redis.cacheNullValues=false", + "spring.cache.redis.keyPrefix=foo", + "spring.cache.redis.useKeyPrefix=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.getTtl()) + .isEqualTo(java.time.Duration.ofSeconds(15)); + assertThat(redisCacheConfiguration.getAllowCacheNullValues()) + .isFalse(); + assertThat(redisCacheConfiguration.getKeyPrefix()).contains("foo"); + assertThat(redisCacheConfiguration.usePrefix()).isFalse(); }); } @@ -309,6 +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.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] ====