From 4a9123d6e34b02a21278fdcc2e2428d966444b64 Mon Sep 17 00:00:00 2001 From: Stephane Nicoll Date: Thu, 11 Jan 2018 11:52:08 +0100 Subject: [PATCH] Detect user-defined RedisCacheConfiguration This commits improves the cache auto-configuration for Redis by looking up a custom "RedisCacheConfiguration" bean that allows to take full control over the `RedisCacheManager`. Closes gh-11599 --- .../cache/RedisCacheConfiguration.java | 16 +++++-- .../cache/CacheAutoConfigurationTests.java | 47 ++++++++++++++++--- .../main/asciidoc/spring-boot-features.adoc | 4 ++ 3 files changed, 56 insertions(+), 11 deletions(-) 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 852fd41f04f..8fd0ddde2f8 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 @@ -1,5 +1,5 @@ /* - * Copyright 2012-2017 the original author or authors. + * Copyright 2012-2018 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -19,6 +19,7 @@ package org.springframework.boot.autoconfigure.cache; import java.util.LinkedHashSet; import java.util.List; +import org.springframework.beans.factory.ObjectProvider; import org.springframework.boot.autoconfigure.AutoConfigureAfter; import org.springframework.boot.autoconfigure.cache.CacheProperties.Redis; import org.springframework.boot.autoconfigure.condition.ConditionalOnBean; @@ -51,16 +52,20 @@ class RedisCacheConfiguration { private final CacheManagerCustomizers customizerInvoker; + private final org.springframework.data.redis.cache.RedisCacheConfiguration redisCacheConfiguration; + RedisCacheConfiguration(CacheProperties cacheProperties, - CacheManagerCustomizers customizerInvoker) { + CacheManagerCustomizers customizerInvoker, + ObjectProvider redisCacheConfiguration) { this.cacheProperties = cacheProperties; this.customizerInvoker = customizerInvoker; + this.redisCacheConfiguration = redisCacheConfiguration.getIfAvailable(); } @Bean public RedisCacheManager cacheManager(RedisConnectionFactory redisConnectionFactory) { RedisCacheManagerBuilder builder = RedisCacheManager - .builder(redisConnectionFactory).cacheDefaults(getConfiguration()); + .builder(redisConnectionFactory).cacheDefaults(determineConfiguration()); List cacheNames = this.cacheProperties.getCacheNames(); if (!cacheNames.isEmpty()) { builder.initialCacheNames(new LinkedHashSet<>(cacheNames)); @@ -68,7 +73,10 @@ class RedisCacheConfiguration { return this.customizerInvoker.customize(builder.build()); } - private org.springframework.data.redis.cache.RedisCacheConfiguration getConfiguration() { + private org.springframework.data.redis.cache.RedisCacheConfiguration determineConfiguration() { + if (this.redisCacheConfiguration != null) { + return this.redisCacheConfiguration; + } Redis redisProperties = this.cacheProperties.getRedis(); org.springframework.data.redis.cache.RedisCacheConfiguration config = org.springframework.data.redis.cache.RedisCacheConfiguration .defaultCacheConfig(); 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 1269e4f0277..7d4f32bbbc3 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 @@ -1,5 +1,5 @@ /* - * Copyright 2012-2017 the original author or authors. + * Copyright 2012-2018 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -279,7 +279,7 @@ public class CacheAutoConfigurationTests { @Test public void redisCacheExplicit() { - this.contextRunner.withUserConfiguration(RedisCacheConfiguration.class) + this.contextRunner.withUserConfiguration(RedisConfiguration.class) .withPropertyValues("spring.cache.type=redis", "spring.cache.redis.time-to-live=15000", "spring.cache.redis.cacheNullValues=false", @@ -300,17 +300,36 @@ public class CacheAutoConfigurationTests { }); } + @Test + public void redisCacheWithRedisCacheConfiguration() { + this.contextRunner + .withUserConfiguration(RedisWithCacheConfigurationConfiguration.class) + .withPropertyValues("spring.cache.type=redis", + "spring.cache.redis.time-to-live=15000", + "spring.cache.redis.keyPrefix=foo") + .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.getTtl()) + .isEqualTo(java.time.Duration.ofSeconds(30)); + assertThat(redisCacheConfiguration.getKeyPrefix()).contains("bar"); + }); + } + @Test public void redisCacheWithCustomizers() { this.contextRunner - .withUserConfiguration(RedisCacheAndCustomizersConfiguration.class) + .withUserConfiguration(RedisWithCustomizersConfiguration.class) .withPropertyValues("spring.cache.type=" + "redis") .run(dunno("allCacheManagerCustomizer", "redisCacheManagerCustomizer")); } @Test public void redisCacheExplicitWithCaches() { - this.contextRunner.withUserConfiguration(RedisCacheConfiguration.class) + this.contextRunner.withUserConfiguration(RedisConfiguration.class) .withPropertyValues("spring.cache.type=redis", "spring.cache.cacheNames[0]=foo", "spring.cache.cacheNames[1]=bar") @@ -919,7 +938,7 @@ public class CacheAutoConfigurationTests { @Configuration @EnableCaching - static class RedisCacheConfiguration { + static class RedisConfiguration { @Bean public RedisConnectionFactory redisConnectionFactory() { @@ -929,8 +948,22 @@ public class CacheAutoConfigurationTests { } @Configuration - @Import({ RedisCacheConfiguration.class, CacheManagerCustomizersConfiguration.class }) - static class RedisCacheAndCustomizersConfiguration { + @Import(RedisConfiguration.class) + static class RedisWithCacheConfigurationConfiguration { + + @Bean + public org.springframework.data.redis.cache.RedisCacheConfiguration customRedisCacheConfiguration() { + return org.springframework.data.redis.cache.RedisCacheConfiguration + .defaultCacheConfig() + .entryTtl(java.time.Duration.ofSeconds(30)) + .prefixKeysWith("bar"); + } + + } + + @Configuration + @Import({ RedisConfiguration.class, CacheManagerCustomizersConfiguration.class }) + static class RedisWithCustomizersConfiguration { } 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 4c4bd500d0d..3e2fe15b93d 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 @@ -4638,6 +4638,10 @@ key, Redis does not have overlapping keys and cannot return invalid values. We s recommend keeping this setting enabled if you create your own `RedisCacheManager`. ==== +TIP: You can take full control of the configuration by adding a `RedisCacheConfiguration` +`@Bean` of your own. This can be useful if you're looking for customizing the +serialization strategy. + [[boot-features-caching-provider-caffeine]]