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(); }); }