From 96aadc2b12bce37237e053b7f7e1c28b98be328b Mon Sep 17 00:00:00 2001 From: Juergen Hoeller Date: Thu, 4 Dec 2025 00:12:13 +0100 Subject: [PATCH] Add resetCaches() method to general CacheManager interface Closes gh-35845 See gh-35840 --- .../cache/jcache/JCacheCacheManager.java | 13 +++++++++ .../cache/jcache/JCacheEhCacheApiTests.java | 17 +++++++++-- .../springframework/cache/CacheManager.java | 28 +++++++++++++++++++ .../cache/support/AbstractCacheManager.java | 7 +++++ .../cache/support/CompositeCacheManager.java | 7 +++++ .../cache/support/NoOpCacheManager.java | 5 ++++ 6 files changed, 75 insertions(+), 2 deletions(-) diff --git a/spring-context-support/src/main/java/org/springframework/cache/jcache/JCacheCacheManager.java b/spring-context-support/src/main/java/org/springframework/cache/jcache/JCacheCacheManager.java index f5d0a9ee2ec..2799fea6d43 100644 --- a/spring-context-support/src/main/java/org/springframework/cache/jcache/JCacheCacheManager.java +++ b/spring-context-support/src/main/java/org/springframework/cache/jcache/JCacheCacheManager.java @@ -130,4 +130,17 @@ public class JCacheCacheManager extends AbstractTransactionSupportingCacheManage return null; } + @Override + public void resetCaches() { + CacheManager cacheManager = getCacheManager(); + if (cacheManager != null && !cacheManager.isClosed()) { + for (String cacheName : cacheManager.getCacheNames()) { + javax.cache.Cache jcache = cacheManager.getCache(cacheName); + if (jcache != null && !jcache.isClosed()) { + jcache.clear(); + } + } + } + } + } diff --git a/spring-context-support/src/test/java/org/springframework/cache/jcache/JCacheEhCacheApiTests.java b/spring-context-support/src/test/java/org/springframework/cache/jcache/JCacheEhCacheApiTests.java index 2117752e658..5ac030e383d 100644 --- a/spring-context-support/src/test/java/org/springframework/cache/jcache/JCacheEhCacheApiTests.java +++ b/spring-context-support/src/test/java/org/springframework/cache/jcache/JCacheEhCacheApiTests.java @@ -51,8 +51,7 @@ class JCacheEhCacheApiTests extends AbstractValueAdaptingCacheTests this.cacheManager.createCache(CACHE_NAME_NO_NULL, new MutableConfiguration<>()); this.nativeCache = this.cacheManager.getCache(CACHE_NAME); this.cache = new JCacheCache(this.nativeCache); - Cache nativeCacheNoNull = - this.cacheManager.getCache(CACHE_NAME_NO_NULL); + Cache nativeCacheNoNull = this.cacheManager.getCache(CACHE_NAME_NO_NULL); this.cacheNoNull = new JCacheCache(nativeCacheNoNull, false); } @@ -100,4 +99,18 @@ class JCacheEhCacheApiTests extends AbstractValueAdaptingCacheTests assertThat(cache.get(key).get()).isEqualTo(value); } + @Test + void resetCaches() { + JCacheCacheManager cm = new JCacheCacheManager(cacheManager); + org.springframework.cache.Cache cache = cm.getCache(CACHE_NAME); + cache.put("key", "value"); + assertThat(cm.getCacheNames()).contains(CACHE_NAME); + assertThat(cm.getCache(CACHE_NAME)).isNotNull().isSameAs(cache); + assertThat(cacheManager.getCache(CACHE_NAME).iterator()).hasNext(); + cm.resetCaches(); + assertThat(cm.getCacheNames()).contains(CACHE_NAME); + assertThat(cm.getCache(CACHE_NAME)).isNotNull().isSameAs(cache); + assertThat(cacheManager.getCache(CACHE_NAME).iterator()).isExhausted(); + } + } diff --git a/spring-context/src/main/java/org/springframework/cache/CacheManager.java b/spring-context/src/main/java/org/springframework/cache/CacheManager.java index 49efba59c09..a59c5677edb 100644 --- a/spring-context/src/main/java/org/springframework/cache/CacheManager.java +++ b/spring-context/src/main/java/org/springframework/cache/CacheManager.java @@ -27,6 +27,7 @@ import org.jspecify.annotations.Nullable; * * @author Costin Leau * @author Sam Brannen + * @author Juergen Hoeller * @since 3.1 */ public interface CacheManager { @@ -47,4 +48,31 @@ public interface CacheManager { */ Collection getCacheNames(); + /** + * Remove all registered caches from this cache manager if possible, + * re-creating them on demand. After this call, {@link #getCacheNames()} + * will possibly be empty and the cache provider will have dropped all + * cache management state. + *

Alternatively, an implementation may perform an equivalent reset + * on fixed existing cache regions without actually dropping the cache. + * This behavior will be indicated by {@link #getCacheNames()} still + * exposing a non-empty set of names, whereas the corresponding cache + * regions will not contain cache entries anymore. + *

The default implementation calls {@link Cache#clear} on all + * registered caches, retaining all caches as registered, satisfying + * the alternative implementation path above. Custom implementations + * may either drop the actual caches (re-creating them on demand) or + * perform a more exhaustive reset at the actual cache provider level. + * @since 7.0.2 + * @see Cache#clear() + */ + default void resetCaches() { + for (String cacheName : getCacheNames()) { + Cache cache = getCache(cacheName); + if (cache != null) { + cache.clear(); + } + } + } + } diff --git a/spring-context/src/main/java/org/springframework/cache/support/AbstractCacheManager.java b/spring-context/src/main/java/org/springframework/cache/support/AbstractCacheManager.java index 4f54605483d..9504c7172e2 100644 --- a/spring-context/src/main/java/org/springframework/cache/support/AbstractCacheManager.java +++ b/spring-context/src/main/java/org/springframework/cache/support/AbstractCacheManager.java @@ -115,6 +115,13 @@ public abstract class AbstractCacheManager implements CacheManager, Initializing return this.cacheNames; } + @Override + public void resetCaches() { + synchronized (this.cacheMap) { + this.cacheMap.values().forEach(Cache::clear); + } + } + // Common cache initialization delegates for subclasses diff --git a/spring-context/src/main/java/org/springframework/cache/support/CompositeCacheManager.java b/spring-context/src/main/java/org/springframework/cache/support/CompositeCacheManager.java index 7ed6b40d62e..911433fb666 100644 --- a/spring-context/src/main/java/org/springframework/cache/support/CompositeCacheManager.java +++ b/spring-context/src/main/java/org/springframework/cache/support/CompositeCacheManager.java @@ -119,4 +119,11 @@ public class CompositeCacheManager implements CacheManager, InitializingBean { return Collections.unmodifiableSet(names); } + @Override + public void resetCaches() { + for (CacheManager manager : this.cacheManagers) { + manager.resetCaches(); + } + } + } diff --git a/spring-context/src/main/java/org/springframework/cache/support/NoOpCacheManager.java b/spring-context/src/main/java/org/springframework/cache/support/NoOpCacheManager.java index ba418e2e0c9..ec192194e09 100644 --- a/spring-context/src/main/java/org/springframework/cache/support/NoOpCacheManager.java +++ b/spring-context/src/main/java/org/springframework/cache/support/NoOpCacheManager.java @@ -55,4 +55,9 @@ public class NoOpCacheManager implements CacheManager { return Collections.unmodifiableSet(this.cacheMap.keySet()); } + @Override + public void resetCaches() { + this.cacheMap.clear(); + } + }