Skip to content

Improve cache auto-configuration for Redis #10944

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 2 commits into from
Nov 10, 2017
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -29,6 +30,7 @@
*
* @author Stephane Nicoll
* @author Eddú Meléndez
* @author Ryon Day
* @since 1.3.0
*/
@ConfigurationProperties(prefix = "spring.cache")
Expand All @@ -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;
}
Expand Down Expand Up @@ -91,6 +95,10 @@ public JCache getJcache() {
return this.jcache;
}

public Redis getRedis() {
return this.redis;
}

/**
* Resolve the config location if set.
* @param config the config resource
Expand Down Expand Up @@ -233,4 +241,69 @@ public void setConfig(Resource config) {

}

/**
* 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;
}
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
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;
Expand All @@ -36,6 +37,7 @@
*
* @author Stephane Nicoll
* @author Mark Paluch
* @author Ryon Day
* @since 1.3.0
*/
@Configuration
Expand All @@ -58,12 +60,34 @@ class RedisCacheConfiguration {
@Bean
public RedisCacheManager cacheManager(RedisConnectionFactory redisConnectionFactory) {
RedisCacheManagerBuilder builder = RedisCacheManager
.builder(redisConnectionFactory);
.builder(redisConnectionFactory).cacheDefaults(getConfiguration());
List<String> 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() != null) {
config = config.prefixKeysWith(redisProperties.getKeyPrefix());
}

if (!redisProperties.isCacheNullValues()) {
config = config.disableCachingNullValues();
}

if (!redisProperties.isUseKeyPrefix()) {
config = config.disableKeyPrefix();
}

return config;
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -90,6 +90,7 @@
* @author Stephane Nicoll
* @author Eddú Meléndez
* @author Mark Paluch
* @author Ryon Day
*/
@RunWith(ModifiedClassPathRunner.class)
@ClassPathExclusions("hazelcast-client-*.jar")
Expand Down Expand Up @@ -280,14 +281,25 @@ public void couchbaseCacheExplicitWithTtl() {
@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();
});
}

Expand All @@ -309,6 +321,15 @@ public void redisCacheExplicitWithCaches() {
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();
});
}

Expand Down