From f6369e8485b785414c182f74025261490201af30 Mon Sep 17 00:00:00 2001 From: Ferdinand Armbruster Date: Mon, 17 Feb 2025 13:32:38 +0100 Subject: [PATCH 1/2] Fix: "BeanInstantiationException" by adding @Require to affected RedisCache-Beans, to avoid unnecessary RedisCache instantiations. Feature: Add "Bypassing"-Cache by existing DynamicCacheManager pattern, if redis is disabled. Feature: Add a dynamic Cache creation without having an explicit configuration by using DefaultCacheConfiguration. Signed-off-by: Ferdinand Armbruster --- gradle.properties | 2 +- .../configuration/lettuce/RedisSetting.java | 6 + .../lettuce/cache/RedisCache.java | 3 +- .../cache/RedisConnectionPoolCache.java | 3 +- .../bypass/BypassDynamicCacheManager.java | 107 ++++++++++++++++++ .../dynamic/RedisDynamicCacheManager.java | 88 ++++++++++++++ .../lettuce/cache/RedisCacheSpec.groovy | 23 +++- .../lettuce/cache/RedisPoolCacheSpec.groovy | 16 ++- .../BypassDynamicCacheManagerSpec.groovy | 44 +++++++ .../RedisDynamicCacheManagerSpec.groovy | 59 ++++++++++ src/main/docs/guide/cache.adoc | 17 +++ src/main/docs/guide/config.adoc | 5 +- 12 files changed, 364 insertions(+), 9 deletions(-) create mode 100644 redis-lettuce/src/main/java/io/micronaut/configuration/lettuce/cache/bypass/BypassDynamicCacheManager.java create mode 100644 redis-lettuce/src/main/java/io/micronaut/configuration/lettuce/cache/dynamic/RedisDynamicCacheManager.java create mode 100644 redis-lettuce/src/test/groovy/io/micronaut/configuration/lettuce/cache/bypass/BypassDynamicCacheManagerSpec.groovy create mode 100644 redis-lettuce/src/test/groovy/io/micronaut/configuration/lettuce/cache/dynamic/RedisDynamicCacheManagerSpec.groovy diff --git a/gradle.properties b/gradle.properties index 1d08ac906..2ec0b51c2 100644 --- a/gradle.properties +++ b/gradle.properties @@ -1,4 +1,4 @@ -projectVersion=6.7.0-SNAPSHOT +projectVersion=6.7.1-SNAPSHOT projectGroup=io.micronaut.redis title=Micronaut Redis diff --git a/redis-lettuce/src/main/java/io/micronaut/configuration/lettuce/RedisSetting.java b/redis-lettuce/src/main/java/io/micronaut/configuration/lettuce/RedisSetting.java index 0d8b21414..e16d84b19 100644 --- a/redis-lettuce/src/main/java/io/micronaut/configuration/lettuce/RedisSetting.java +++ b/redis-lettuce/src/main/java/io/micronaut/configuration/lettuce/RedisSetting.java @@ -46,6 +46,12 @@ public interface RedisSetting { * Default configuration for Redis caches. */ String REDIS_CACHE = PREFIX + ".cache"; + + /** + * Configuration for dynamic Redis caches. + */ + String REDIS_DYNAMIC_CACHE = REDIS_CACHE + ".dynamic"; + /** * Configured Redis caches. */ diff --git a/redis-lettuce/src/main/java/io/micronaut/configuration/lettuce/cache/RedisCache.java b/redis-lettuce/src/main/java/io/micronaut/configuration/lettuce/cache/RedisCache.java index bfc23d064..9c1320418 100644 --- a/redis-lettuce/src/main/java/io/micronaut/configuration/lettuce/cache/RedisCache.java +++ b/redis-lettuce/src/main/java/io/micronaut/configuration/lettuce/cache/RedisCache.java @@ -46,10 +46,11 @@ /** * An implementation of {@link SyncCache} for Lettuce / Redis. * - * @author Graeme Rocher + * @author Graeme Rocher, Ferdinand Armbruster * @since 1.0 */ @EachBean(RedisCacheConfiguration.class) +@Requires(classes = SyncCache.class, property = RedisSetting.PREFIX + ".enabled", defaultValue = StringUtils.TRUE, notEquals = StringUtils.FALSE) @Requires(classes = SyncCache.class, property = RedisSetting.REDIS_POOL + ".enabled", defaultValue = StringUtils.FALSE, notEquals = StringUtils.TRUE) public class RedisCache extends AbstractRedisCache> { private final RedisAsyncCache asyncCache; diff --git a/redis-lettuce/src/main/java/io/micronaut/configuration/lettuce/cache/RedisConnectionPoolCache.java b/redis-lettuce/src/main/java/io/micronaut/configuration/lettuce/cache/RedisConnectionPoolCache.java index 455db811e..be180a40f 100644 --- a/redis-lettuce/src/main/java/io/micronaut/configuration/lettuce/cache/RedisConnectionPoolCache.java +++ b/redis-lettuce/src/main/java/io/micronaut/configuration/lettuce/cache/RedisConnectionPoolCache.java @@ -51,10 +51,11 @@ /** * An implementation of {@link SyncCache} for Lettuce / Redis using connection pooling. * - * @author Graeme Rocher, Kovalov Illia + * @author Graeme Rocher, Kovalov Illia, Ferdinand Armbruster * @since 5.3.0 */ @EachBean(RedisCacheConfiguration.class) +@Requires(classes = SyncCache.class, property = RedisSetting.PREFIX + ".enabled", defaultValue = StringUtils.TRUE, notEquals = StringUtils.FALSE) @Requires(classes = SyncCache.class, property = RedisSetting.REDIS_POOL + ".enabled", defaultValue = StringUtils.FALSE, notEquals = StringUtils.FALSE) public class RedisConnectionPoolCache extends AbstractRedisCache>> { private static final Logger LOG = LoggerFactory.getLogger(RedisConnectionPoolCache.class); diff --git a/redis-lettuce/src/main/java/io/micronaut/configuration/lettuce/cache/bypass/BypassDynamicCacheManager.java b/redis-lettuce/src/main/java/io/micronaut/configuration/lettuce/cache/bypass/BypassDynamicCacheManager.java new file mode 100644 index 000000000..9fb274361 --- /dev/null +++ b/redis-lettuce/src/main/java/io/micronaut/configuration/lettuce/cache/bypass/BypassDynamicCacheManager.java @@ -0,0 +1,107 @@ +/* + * Copyright 2017-2024 original authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package io.micronaut.configuration.lettuce.cache.bypass; + +import io.micronaut.cache.DynamicCacheManager; +import io.micronaut.cache.SyncCache; +import io.micronaut.configuration.lettuce.RedisSetting; +import io.micronaut.context.annotation.Requires; +import io.micronaut.core.annotation.NonNull; +import io.micronaut.core.type.Argument; +import io.micronaut.core.util.StringUtils; +import jakarta.inject.Singleton; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.util.Optional; +import java.util.function.Supplier; + +/** + * An implementation of {@link DynamicCacheManager} to bypass the caching mechanism, if redis is deactivated. + * + * @author Armbruster Ferdinand + * @since 6.7.1 + */ +@Singleton +@Requires(classes = SyncCache.class, property = RedisSetting.PREFIX + ".enabled", defaultValue = StringUtils.TRUE, notEquals = StringUtils.TRUE) +public class BypassDynamicCacheManager implements DynamicCacheManager { + + private static final Logger LOG = LoggerFactory.getLogger(BypassDynamicCacheManager.class); + + /** + * Creates a new bypass cache for the given arguments. + * + * @param name The name of the dynamic cache + */ + @Override + public @NonNull SyncCache getCache(String name) { + if (LOG.isDebugEnabled()) { + LOG.debug("Create BypassCache for {}", name); + } + return new BypassCache(name); + } + + /** + * An implementation of {@link SyncCache} to bypass the caching mechanism. + * + * @author Armbruster Ferdinand + * @since 6.7.1 + */ + protected class BypassCache implements SyncCache { + + private final String name; + + public BypassCache(String name) { + this.name = name; + } + + @Override + public @NonNull Optional get(@NonNull Object key, @NonNull Argument requiredType) { + return Optional.empty(); + } + + @Override + public T get(@NonNull Object key, @NonNull Argument requiredType, @NonNull Supplier supplier) { + return null; + } + + @Override + public @NonNull Optional putIfAbsent(@NonNull Object key, @NonNull T value) { + return Optional.empty(); + } + + @Override + public void put(@NonNull Object key, @NonNull Object value) { } + + @Override + public void invalidate(@NonNull Object key) { } + + @Override + public void invalidateAll() { } + + @Override + public String getName() { + return name; + } + + @Override + public Object getNativeCache() { + return null; + } + } + +} + diff --git a/redis-lettuce/src/main/java/io/micronaut/configuration/lettuce/cache/dynamic/RedisDynamicCacheManager.java b/redis-lettuce/src/main/java/io/micronaut/configuration/lettuce/cache/dynamic/RedisDynamicCacheManager.java new file mode 100644 index 000000000..817245ffe --- /dev/null +++ b/redis-lettuce/src/main/java/io/micronaut/configuration/lettuce/cache/dynamic/RedisDynamicCacheManager.java @@ -0,0 +1,88 @@ +/* + * Copyright 2017-2024 original authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package io.micronaut.configuration.lettuce.cache.dynamic; + +import io.lettuce.core.api.StatefulConnection; +import io.micronaut.cache.DynamicCacheManager; +import io.micronaut.cache.SyncCache; +import io.micronaut.configuration.lettuce.RedisSetting; +import io.micronaut.configuration.lettuce.cache.DefaultRedisCacheConfiguration; +import io.micronaut.configuration.lettuce.cache.RedisCache; +import io.micronaut.configuration.lettuce.cache.RedisCacheConfiguration; +import io.micronaut.configuration.lettuce.cache.bypass.BypassDynamicCacheManager; +import io.micronaut.context.BeanLocator; +import io.micronaut.context.annotation.Requires; +import io.micronaut.core.annotation.NonNull; +import io.micronaut.core.convert.ConversionService; +import io.micronaut.core.util.StringUtils; +import io.micronaut.runtime.ApplicationConfiguration; +import jakarta.inject.Singleton; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + + +/** + * An implementation of {@link DynamicCacheManager} for to create caches without having a configuration entry. + * By using default {@link DefaultRedisCacheConfiguration}. + * + * @author Armbruster Ferdinand + * @since 6.7.1 + */ +@Singleton +@Requires(classes = SyncCache.class, property = RedisSetting.PREFIX + ".enabled", defaultValue = StringUtils.TRUE, notEquals = StringUtils.FALSE) +@Requires(classes = SyncCache.class, property = RedisSetting.REDIS_DYNAMIC_CACHE + ".enabled", defaultValue = StringUtils.FALSE, notEquals = StringUtils.FALSE) +public class RedisDynamicCacheManager implements DynamicCacheManager> { + + private static final Logger LOG = LoggerFactory.getLogger(BypassDynamicCacheManager.class); + + private ApplicationConfiguration applicationConfiguration; + private DefaultRedisCacheConfiguration defaultRedisCacheConfiguration; + private ConversionService conversionService; + private BeanLocator beanLocator; + + public RedisDynamicCacheManager( + ApplicationConfiguration applicationConfiguration, + DefaultRedisCacheConfiguration defaultRedisCacheConfiguration, + ConversionService conversionService, + BeanLocator beanLocator + ) { + this.applicationConfiguration = applicationConfiguration; + this.defaultRedisCacheConfiguration = defaultRedisCacheConfiguration; + this.conversionService = conversionService; + this.beanLocator = beanLocator; + } + + /** + * Creates a new dynamic redis cache for the given arguments. + * + * @param name The name of the dynamic cache + */ + @Override + public @NonNull SyncCache> getCache(String name) { + + if (LOG.isDebugEnabled()) { + LOG.debug("Create DynamicRedisCache for {}", name); + } + + return new RedisCache( + defaultRedisCacheConfiguration, + new RedisCacheConfiguration(name, applicationConfiguration), + conversionService, + beanLocator + ); + } +} + diff --git a/redis-lettuce/src/test/groovy/io/micronaut/configuration/lettuce/cache/RedisCacheSpec.groovy b/redis-lettuce/src/test/groovy/io/micronaut/configuration/lettuce/cache/RedisCacheSpec.groovy index c74e9f6ea..f89dabad3 100644 --- a/redis-lettuce/src/test/groovy/io/micronaut/configuration/lettuce/cache/RedisCacheSpec.groovy +++ b/redis-lettuce/src/test/groovy/io/micronaut/configuration/lettuce/cache/RedisCacheSpec.groovy @@ -8,6 +8,7 @@ import io.micronaut.configuration.lettuce.RedisSpec import io.micronaut.context.ApplicationContext import io.micronaut.context.BeanLocator import io.micronaut.context.exceptions.ConfigurationException +import io.micronaut.context.exceptions.NoSuchBeanException import io.micronaut.core.convert.ConversionService import io.micronaut.core.type.Argument import io.micronaut.inject.qualifiers.Qualifiers @@ -21,17 +22,31 @@ import java.nio.charset.Charset import java.util.concurrent.ExecutionException /** - * @author Graeme Rocher + * @author Graeme Rocher, Ferdinand Armbruster * @since 1.0 */ class RedisCacheSpec extends RedisSpec { - ApplicationContext createApplicationContext() { - ApplicationContext.run( + ApplicationContext createApplicationContext(Map options = [:]) { + ApplicationContext.run([ 'redis.port': RedisContainerUtils.getRedisPort(), 'redis.caches.test.enabled': 'true', 'redis.caches.test.invalidate-scan-count': 2 - ) + ] + options) + } + + void "test bean is not instantiated if redis is disabled"(){ + setup: + ApplicationContext applicationContext = createApplicationContext(['redis.enabled': false]) + + when: + applicationContext.getBean(RedisCache, Qualifiers.byName("test")) + + then: + thrown(NoSuchBeanException) + + cleanup: + applicationContext.stop() } void "test read/write object from redis sync cache"() { diff --git a/redis-lettuce/src/test/groovy/io/micronaut/configuration/lettuce/cache/RedisPoolCacheSpec.groovy b/redis-lettuce/src/test/groovy/io/micronaut/configuration/lettuce/cache/RedisPoolCacheSpec.groovy index 5d7d9e7a7..1d473608a 100644 --- a/redis-lettuce/src/test/groovy/io/micronaut/configuration/lettuce/cache/RedisPoolCacheSpec.groovy +++ b/redis-lettuce/src/test/groovy/io/micronaut/configuration/lettuce/cache/RedisPoolCacheSpec.groovy @@ -17,7 +17,7 @@ import io.micronaut.runtime.ApplicationConfiguration import java.nio.charset.Charset /** - * @author Kovalov Illia + * @author Kovalov Illia, Ferdinand Armbruster */ class RedisPoolCacheSpec extends RedisSpec { @@ -29,6 +29,20 @@ class RedisPoolCacheSpec extends RedisSpec { ] + options).environments("test").eagerInitSingletons(eagerInit).start() } + void "test bean is not instantiated if redis is disabled"(){ + setup: + ApplicationContext applicationContext = createApplicationContext('redis.enabled': 'false') + + when: + applicationContext.getBean(RedisCache, Qualifiers.byName("test")) + + then: + thrown(NoSuchBeanException) + + cleanup: + applicationContext.stop() + } + void "can be disabled where initialization is #description"() { setup: ApplicationContext applicationContext = createApplicationContext('redis.pool.enabled': 'false', eager) diff --git a/redis-lettuce/src/test/groovy/io/micronaut/configuration/lettuce/cache/bypass/BypassDynamicCacheManagerSpec.groovy b/redis-lettuce/src/test/groovy/io/micronaut/configuration/lettuce/cache/bypass/BypassDynamicCacheManagerSpec.groovy new file mode 100644 index 000000000..49272ed24 --- /dev/null +++ b/redis-lettuce/src/test/groovy/io/micronaut/configuration/lettuce/cache/bypass/BypassDynamicCacheManagerSpec.groovy @@ -0,0 +1,44 @@ +package io.micronaut.configuration.lettuce.cache.bypass + + +import io.micronaut.configuration.lettuce.RedisSpec +import io.micronaut.context.ApplicationContext +import io.micronaut.context.exceptions.NoSuchBeanException + +/** + * @author Ferdinand Armbruster + * @since 1.0 + */ +class BypassDynamicCacheManagerSpec extends RedisSpec { + + + ApplicationContext createApplicationContext(Boolean enabled) { + ApplicationContext.run(["redis.enabled": enabled]) + } + + + void "test BypassDynamicCacheManager should not be available if redis is active"() { + setup: + ApplicationContext applicationContext = createApplicationContext(true) + + when: + applicationContext.getBean(BypassDynamicCacheManager) + + then: + thrown(NoSuchBeanException) + } + + void "test bypassCache"() { + setup: + ApplicationContext applicationContext = createApplicationContext(false) + + when: + BypassDynamicCacheManager bypassDynamicCacheManager = applicationContext.getBean(BypassDynamicCacheManager) + BypassDynamicCacheManager.BypassCache bypassCache = bypassDynamicCacheManager.getCache("test") + + then: + bypassDynamicCacheManager != null + bypassCache != null + } + +} diff --git a/redis-lettuce/src/test/groovy/io/micronaut/configuration/lettuce/cache/dynamic/RedisDynamicCacheManagerSpec.groovy b/redis-lettuce/src/test/groovy/io/micronaut/configuration/lettuce/cache/dynamic/RedisDynamicCacheManagerSpec.groovy new file mode 100644 index 000000000..0a956eff7 --- /dev/null +++ b/redis-lettuce/src/test/groovy/io/micronaut/configuration/lettuce/cache/dynamic/RedisDynamicCacheManagerSpec.groovy @@ -0,0 +1,59 @@ +package io.micronaut.configuration.lettuce.cache.dynamic + +import io.lettuce.core.api.StatefulRedisConnection +import io.micronaut.configuration.lettuce.RedisSpec +import io.micronaut.configuration.lettuce.cache.RedisCache +import io.micronaut.context.ApplicationContext +import io.micronaut.context.exceptions.NoSuchBeanException +import io.micronaut.redis.test.RedisContainerUtils + +/** + * @author Ferdinand Armbruster + * @since 6.7.1 + */ +class RedisDynamicCacheManagerSpec extends RedisSpec { + + ApplicationContext createApplicationContext(boolean redisEnabled = true, boolean dynamicEnabled = true) { + ApplicationContext.run([ + "redis.enabled" : redisEnabled, + 'redis.port' : RedisContainerUtils.getRedisPort(), + "redis.cache.dynamic.enabled": dynamicEnabled + ]) + } + + void "test RedisDynamicCacheManager should not be available if redis is deactivated"() { + setup: + ApplicationContext applicationContext = createApplicationContext(false, true) + + when: + applicationContext.getBean(RedisDynamicCacheManager) + + then: + thrown(NoSuchBeanException) + } + + void "test RedisDynamicCacheManager should not be available if dynamic is deactivated"() { + setup: + ApplicationContext applicationContext = createApplicationContext(true, false) + + when: + applicationContext.getBean(RedisDynamicCacheManager) + + then: + thrown(NoSuchBeanException) + } + + void "test creation of redisCache object for given name"() { + setup: + ApplicationContext applicationContext = createApplicationContext(true, true) + + when: + RedisDynamicCacheManager redisDynamicCacheManager = applicationContext.getBean(RedisDynamicCacheManager) + RedisCache redisCache = redisDynamicCacheManager.getCache("test") + + then: + redisCache != null + redisCache.getNativeCache() instanceof StatefulRedisConnection + } + +} diff --git a/src/main/docs/guide/cache.adoc b/src/main/docs/guide/cache.adoc index cbcf08793..04baf9b81 100644 --- a/src/main/docs/guide/cache.adoc +++ b/src/main/docs/guide/cache.adoc @@ -27,3 +27,20 @@ redis: - Expiration is based on result from an implementation of api:configuration.lettuce.cache.expiration.ExpirationAfterWritePolicy[] include::{includedir}configurationProperties/io.micronaut.configuration.lettuce.cache.RedisCacheConfiguration.adoc[] + +== Dynamic Caching + +To get more flexibilty to about Caches, you can enable dynamic caching. Therefore no specific cache configuration is needed and the caches will be created dynamically at runtime. +The DefaultRedisCacheConfiguration will be used to setup the cache. "Static"- and "Dynamic"-caches can be used in parallel. + +.DynamicCache Configuration Example +[configuration] +---- +redis: + uri: redis://localhost + cache: + dynamic: + enabled: true + expire-after-write: 1h + expiration-after-write-policy: +---- diff --git a/src/main/docs/guide/config.adoc b/src/main/docs/guide/config.adoc index 656b0b6d9..f50a7322e 100644 --- a/src/main/docs/guide/config.adoc +++ b/src/main/docs/guide/config.adoc @@ -80,7 +80,7 @@ include::{testsredis}/NamedCodecFactory.groovy[tags=namedCodec2, indent=0] When the `redis-lettuce` module is activated a api:configuration.lettuce.health.RedisHealthIndicator[] is activated resulting in the `/health` endpoint and https://docs.micronaut.io/latest/api/io/micronaut/health/CurrentHealthStatus.html[CurrentHealthStatus] interface resolving the health of the Redis connection or connections. -The health indicator is enabled by default. To disable the health endpoint, you can do so via the config. +The health indicator is enabled by default. To disable the health endpoint, you can do so via the config. [configuration] ---- redis: @@ -100,3 +100,6 @@ You can disable the creation of Redis connections using the `redis.enabled` sett redis: enabled: false ---- + +If redis is disabled, the caching functionality will also be disabled and bypassed. + From da8611e9730a15517617e5743e2fd347712002dd Mon Sep 17 00:00:00 2001 From: Ferdinand Armbruster Date: Mon, 17 Feb 2025 13:32:38 +0100 Subject: [PATCH 2/2] Fix: "BeanInstantiationException" by adding @Require to affected RedisCache-Beans, to avoid unnecessary RedisCache instantiations. Feature: Add "Bypassing"-Cache by existing DynamicCacheManager pattern, if redis is disabled. Feature: Add a dynamic Cache creation without having an explicit configuration by using DefaultCacheConfiguration. Signed-off-by: Ferdinand Armbruster --- .../lettuce/cache/bypass/BypassDynamicCacheManagerSpec.groovy | 3 ++- src/main/docs/guide/cache.adoc | 2 +- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/redis-lettuce/src/test/groovy/io/micronaut/configuration/lettuce/cache/bypass/BypassDynamicCacheManagerSpec.groovy b/redis-lettuce/src/test/groovy/io/micronaut/configuration/lettuce/cache/bypass/BypassDynamicCacheManagerSpec.groovy index 49272ed24..2db801594 100644 --- a/redis-lettuce/src/test/groovy/io/micronaut/configuration/lettuce/cache/bypass/BypassDynamicCacheManagerSpec.groovy +++ b/redis-lettuce/src/test/groovy/io/micronaut/configuration/lettuce/cache/bypass/BypassDynamicCacheManagerSpec.groovy @@ -7,7 +7,8 @@ import io.micronaut.context.exceptions.NoSuchBeanException /** * @author Ferdinand Armbruster - * @since 1.0 + * + * @since 6.7.1 */ class BypassDynamicCacheManagerSpec extends RedisSpec { diff --git a/src/main/docs/guide/cache.adoc b/src/main/docs/guide/cache.adoc index 04baf9b81..f89eac87b 100644 --- a/src/main/docs/guide/cache.adoc +++ b/src/main/docs/guide/cache.adoc @@ -30,7 +30,7 @@ include::{includedir}configurationProperties/io.micronaut.configuration.lettuce. == Dynamic Caching -To get more flexibilty to about Caches, you can enable dynamic caching. Therefore no specific cache configuration is needed and the caches will be created dynamically at runtime. +To get more flexibility for Caches, you can enable dynamic caching. Therefore no specific cache configuration is needed and the caches will be created dynamically at runtime. The DefaultRedisCacheConfiguration will be used to setup the cache. "Static"- and "Dynamic"-caches can be used in parallel. .DynamicCache Configuration Example