Merge pull request #10944 from ryonday:redis-cache-config

* pr/10944:
  Polish "Improve cache auto-configuration for Redis"
  Improve cache auto-configuration for Redis
  Respond to MR feedback
  Improve spring-boot-autoconfigure for Redis caches
pull/10387/head
Stephane Nicoll 7 years ago
commit c40517b0ce

@ -29,6 +29,7 @@ import org.springframework.util.Assert;
* *
* @author Stephane Nicoll * @author Stephane Nicoll
* @author Eddú Meléndez * @author Eddú Meléndez
* @author Ryon Day
* @since 1.3.0 * @since 1.3.0
*/ */
@ConfigurationProperties(prefix = "spring.cache") @ConfigurationProperties(prefix = "spring.cache")
@ -55,6 +56,8 @@ public class CacheProperties {
private final JCache jcache = new JCache(); private final JCache jcache = new JCache();
private final Redis redis = new Redis();
public CacheType getType() { public CacheType getType() {
return this.type; return this.type;
} }
@ -91,6 +94,10 @@ public class CacheProperties {
return this.jcache; return this.jcache;
} }
public Redis getRedis() {
return this.redis;
}
/** /**
* Resolve the config location if set. * Resolve the config location if set.
* @param config the config resource * @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;
}
}
} }

@ -16,10 +16,12 @@
package org.springframework.boot.autoconfigure.cache; package org.springframework.boot.autoconfigure.cache;
import java.time.Duration;
import java.util.LinkedHashSet; import java.util.LinkedHashSet;
import java.util.List; import java.util.List;
import org.springframework.boot.autoconfigure.AutoConfigureAfter; 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.ConditionalOnBean;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.boot.autoconfigure.data.redis.RedisAutoConfiguration; import org.springframework.boot.autoconfigure.data.redis.RedisAutoConfiguration;
@ -36,6 +38,7 @@ import org.springframework.data.redis.connection.RedisConnectionFactory;
* *
* @author Stephane Nicoll * @author Stephane Nicoll
* @author Mark Paluch * @author Mark Paluch
* @author Ryon Day
* @since 1.3.0 * @since 1.3.0
*/ */
@Configuration @Configuration
@ -58,7 +61,7 @@ class RedisCacheConfiguration {
@Bean @Bean
public RedisCacheManager cacheManager(RedisConnectionFactory redisConnectionFactory) { public RedisCacheManager cacheManager(RedisConnectionFactory redisConnectionFactory) {
RedisCacheManagerBuilder builder = RedisCacheManager RedisCacheManagerBuilder builder = RedisCacheManager
.builder(redisConnectionFactory); .builder(redisConnectionFactory).cacheDefaults(getConfiguration());
List<String> cacheNames = this.cacheProperties.getCacheNames(); List<String> cacheNames = this.cacheProperties.getCacheNames();
if (!cacheNames.isEmpty()) { if (!cacheNames.isEmpty()) {
builder.initialCacheNames(new LinkedHashSet<>(cacheNames)); builder.initialCacheNames(new LinkedHashSet<>(cacheNames));
@ -66,4 +69,21 @@ class RedisCacheConfiguration {
return this.customizerInvoker.customize(builder.build()); 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;
}
} }

@ -90,6 +90,7 @@ import static org.mockito.Mockito.verify;
* @author Stephane Nicoll * @author Stephane Nicoll
* @author Eddú Meléndez * @author Eddú Meléndez
* @author Mark Paluch * @author Mark Paluch
* @author Ryon Day
*/ */
@RunWith(ModifiedClassPathRunner.class) @RunWith(ModifiedClassPathRunner.class)
@ClassPathExclusions("hazelcast-client-*.jar") @ClassPathExclusions("hazelcast-client-*.jar")
@ -280,14 +281,23 @@ public class CacheAutoConfigurationTests {
@Test @Test
public void redisCacheExplicit() { public void redisCacheExplicit() {
this.contextRunner.withUserConfiguration(RedisCacheConfiguration.class) 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 cacheManager = getCacheManager(context,
RedisCacheManager.class); RedisCacheManager.class);
assertThat(cacheManager.getCacheNames()).isEmpty(); assertThat(cacheManager.getCacheNames()).isEmpty();
assertThat( org.springframework.data.redis.cache.RedisCacheConfiguration redisCacheConfiguration = (org.springframework.data.redis.cache.RedisCacheConfiguration) new DirectFieldAccessor(
((org.springframework.data.redis.cache.RedisCacheConfiguration) new DirectFieldAccessor( cacheManager).getPropertyValue("defaultCacheConfig");
cacheManager).getPropertyValue("defaultCacheConfig")) assertThat(redisCacheConfiguration.getTtl())
.usePrefix()).isTrue(); .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 cacheManager = getCacheManager(context,
RedisCacheManager.class); RedisCacheManager.class);
assertThat(cacheManager.getCacheNames()).containsOnly("foo", "bar"); 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();
}); });
} }

@ -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.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.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.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.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]) # SPRING CONFIG - using environment property only ({sc-spring-boot}/context/config/ConfigFileApplicationListener.{sc-ext}[ConfigFileApplicationListener])

@ -4546,9 +4546,17 @@ This sample configuration reuses the `Cluster` that was created via auto-configu
[[boot-features-caching-provider-redis]] [[boot-features-caching-provider-redis]]
==== Redis ==== Redis
If Redis is available and configured, the `RedisCacheManager` is auto-configured. It is If Redis is available and configured, a `RedisCacheManager` is auto-configured. It is
also possible to create additional caches on startup by setting the possible to create additional caches on startup by setting the
`spring.cache.cache-names` property. `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] [NOTE]
==== ====

Loading…
Cancel
Save