Browse Source

Add resetCaches() method to Caffeine/ConcurrentMapCacheManager

Closes gh-35840

(cherry picked from commit bc3431f435)
pull/35859/head
Juergen Hoeller 4 weeks ago
parent
commit
8545a759a7
  1. 57
      spring-context-support/src/main/java/org/springframework/cache/caffeine/CaffeineCacheManager.java
  2. 24
      spring-context-support/src/test/java/org/springframework/cache/caffeine/CaffeineCacheManagerTests.java
  3. 37
      spring-context/src/main/java/org/springframework/cache/concurrent/ConcurrentMapCacheManager.java
  4. 24
      spring-context/src/test/java/org/springframework/cache/concurrent/ConcurrentMapCacheManagerTests.java

57
spring-context-support/src/main/java/org/springframework/cache/caffeine/CaffeineCacheManager.java vendored

@ -77,7 +77,7 @@ public class CaffeineCacheManager implements CacheManager { @@ -77,7 +77,7 @@ public class CaffeineCacheManager implements CacheManager {
private boolean allowNullValues = true;
private boolean dynamic = true;
private volatile boolean dynamic = true;
private final Map<String, Cache> cacheMap = new ConcurrentHashMap<>(16);
@ -102,10 +102,15 @@ public class CaffeineCacheManager implements CacheManager { @@ -102,10 +102,15 @@ public class CaffeineCacheManager implements CacheManager {
/**
* Specify the set of cache names for this CacheManager's 'static' mode.
* <p>The number of caches and their names will be fixed after a call to this method,
* with no creation of further cache regions at runtime.
* <p>Calling this with a {@code null} collection argument resets the
* mode to 'dynamic', allowing for further creation of caches again.
* <p>The number of caches and their names will be fixed after a call
* to this method, with no creation of further cache regions at runtime.
* <p>Note that this method replaces existing caches of the given names
* and prevents the creation of further cache regions from here on - but
* does <i>not</i> remove unrelated existing caches. For a full reset,
* consider calling {@link #resetCaches()} before calling this method.
* <p>Calling this method with a {@code null} collection argument resets
* the mode to 'dynamic', allowing for further creation of caches again.
* @see #resetCaches()
*/
public void setCacheNames(@Nullable Collection<String> cacheNames) {
if (cacheNames != null) {
@ -245,11 +250,6 @@ public class CaffeineCacheManager implements CacheManager { @@ -245,11 +250,6 @@ public class CaffeineCacheManager implements CacheManager {
}
@Override
public Collection<String> getCacheNames() {
return Collections.unmodifiableSet(this.cacheMap.keySet());
}
@Override
@Nullable
public Cache getCache(String name) {
@ -260,6 +260,33 @@ public class CaffeineCacheManager implements CacheManager { @@ -260,6 +260,33 @@ public class CaffeineCacheManager implements CacheManager {
return cache;
}
@Override
public Collection<String> getCacheNames() {
return Collections.unmodifiableSet(this.cacheMap.keySet());
}
/**
* Reset this cache manager's caches, removing them completely for on-demand
* re-creation in 'dynamic' mode, or simply clearing their entries otherwise.
* @since 6.2.14
*/
public void resetCaches() {
this.cacheMap.values().forEach(Cache::clear);
if (this.dynamic) {
this.cacheMap.keySet().retainAll(this.customCacheNames);
}
}
/**
* Remove the specified cache from this cache manager, applying to
* custom caches as well as dynamically registered caches at runtime.
* @param name the name of the cache
* @since 6.1.15
*/
public void removeCache(String name) {
this.customCacheNames.remove(name);
this.cacheMap.remove(name);
}
/**
* Register the given native Caffeine Cache instance with this cache manager,
@ -303,16 +330,6 @@ public class CaffeineCacheManager implements CacheManager { @@ -303,16 +330,6 @@ public class CaffeineCacheManager implements CacheManager {
this.cacheMap.put(name, adaptCaffeineCache(name, cache));
}
/**
* Remove the specified cache from this cache manager, applying to
* custom caches as well as dynamically registered caches at runtime.
* @param name the name of the cache
* @since 6.1.15
*/
public void removeCache(String name) {
this.customCacheNames.remove(name);
this.cacheMap.remove(name);
}
/**
* Adapt the given new native Caffeine Cache instance to Spring's {@link Cache}

24
spring-context-support/src/test/java/org/springframework/cache/caffeine/CaffeineCacheManagerTests.java vendored

@ -24,7 +24,6 @@ import com.github.benmanes.caffeine.cache.CaffeineSpec; @@ -24,7 +24,6 @@ import com.github.benmanes.caffeine.cache.CaffeineSpec;
import org.junit.jupiter.api.Test;
import org.springframework.cache.Cache;
import org.springframework.cache.CacheManager;
import org.springframework.cache.support.SimpleValueWrapper;
import static org.assertj.core.api.Assertions.assertThat;
@ -42,7 +41,7 @@ class CaffeineCacheManagerTests { @@ -42,7 +41,7 @@ class CaffeineCacheManagerTests {
@Test
@SuppressWarnings("cast")
void dynamicMode() {
CacheManager cm = new CaffeineCacheManager();
CaffeineCacheManager cm = new CaffeineCacheManager();
Cache cache1 = cm.getCache("c1");
assertThat(cache1).isInstanceOf(CaffeineCache.class);
@ -76,6 +75,14 @@ class CaffeineCacheManagerTests { @@ -76,6 +75,14 @@ class CaffeineCacheManagerTests {
cache1.evict("key3");
assertThat(cache1.get("key3", () -> (String) null)).isNull();
assertThat(cache1.get("key3", () -> (String) null)).isNull();
cm.removeCache("c1");
assertThat(cm.getCache("c1")).isNotSameAs(cache1);
assertThat(cm.getCache("c2")).isSameAs(cache2);
cm.resetCaches();
assertThat(cm.getCache("c1")).isNotSameAs(cache1);
assertThat(cm.getCache("c2")).isNotSameAs(cache2);
}
@Test
@ -131,11 +138,24 @@ class CaffeineCacheManagerTests { @@ -131,11 +138,24 @@ class CaffeineCacheManagerTests {
cm.setAllowNullValues(true);
Cache cache1y = cm.getCache("c1");
Cache cache2y = cm.getCache("c2");
cache1y.put("key3", null);
assertThat(cache1y.get("key3").get()).isNull();
cache1y.evict("key3");
assertThat(cache1y.get("key3")).isNull();
cache2y.put("key4", "value4");
assertThat(cache2y.get("key4").get()).isEqualTo("value4");
cm.removeCache("c1");
assertThat(cm.getCache("c1")).isNull();
assertThat(cm.getCache("c2")).isSameAs(cache2y);
assertThat(cache2y.get("key4").get()).isEqualTo("value4");
cm.resetCaches();
assertThat(cm.getCache("c1")).isNull();
assertThat(cm.getCache("c2")).isSameAs(cache2y);
assertThat(cache2y.get("key4")).isNull();
}
@Test

37
spring-context/src/main/java/org/springframework/cache/concurrent/ConcurrentMapCacheManager.java vendored

@ -54,7 +54,7 @@ public class ConcurrentMapCacheManager implements CacheManager, BeanClassLoaderA @@ -54,7 +54,7 @@ public class ConcurrentMapCacheManager implements CacheManager, BeanClassLoaderA
private final ConcurrentMap<String, Cache> cacheMap = new ConcurrentHashMap<>(16);
private boolean dynamic = true;
private volatile boolean dynamic = true;
private boolean allowNullValues = true;
@ -82,10 +82,15 @@ public class ConcurrentMapCacheManager implements CacheManager, BeanClassLoaderA @@ -82,10 +82,15 @@ public class ConcurrentMapCacheManager implements CacheManager, BeanClassLoaderA
/**
* Specify the set of cache names for this CacheManager's 'static' mode.
* <p>The number of caches and their names will be fixed after a call to this method,
* with no creation of further cache regions at runtime.
* <p>Calling this with a {@code null} collection argument resets the
* mode to 'dynamic', allowing for further creation of caches again.
* <p>The number of caches and their names will be fixed after a call
* to this method, with no creation of further cache regions at runtime.
* <p>Note that this method replaces existing caches of the given names
* and prevents the creation of further cache regions from here on - but
* does <i>not</i> remove unrelated existing caches. For a full reset,
* consider calling {@link #resetCaches()} before calling this method.
* <p>Calling this method with a {@code null} collection argument resets
* the mode to 'dynamic', allowing for further creation of caches again.
* @see #resetCaches()
*/
public void setCacheNames(@Nullable Collection<String> cacheNames) {
if (cacheNames != null) {
@ -160,11 +165,6 @@ public class ConcurrentMapCacheManager implements CacheManager, BeanClassLoaderA @@ -160,11 +165,6 @@ public class ConcurrentMapCacheManager implements CacheManager, BeanClassLoaderA
}
@Override
public Collection<String> getCacheNames() {
return Collections.unmodifiableSet(this.cacheMap.keySet());
}
@Override
@Nullable
public Cache getCache(String name) {
@ -175,6 +175,23 @@ public class ConcurrentMapCacheManager implements CacheManager, BeanClassLoaderA @@ -175,6 +175,23 @@ public class ConcurrentMapCacheManager implements CacheManager, BeanClassLoaderA
return cache;
}
@Override
public Collection<String> getCacheNames() {
return Collections.unmodifiableSet(this.cacheMap.keySet());
}
/**
* Reset this cache manager's caches, removing them completely for on-demand
* re-creation in 'dynamic' mode, or simply clearing their entries otherwise.
* @since 6.2.14
*/
public void resetCaches() {
this.cacheMap.values().forEach(Cache::clear);
if (this.dynamic) {
this.cacheMap.clear();
}
}
/**
* Remove the specified cache from this cache manager.
* @param name the name of the cache

24
spring-context/src/test/java/org/springframework/cache/concurrent/ConcurrentMapCacheManagerTests.java vendored

@ -19,7 +19,6 @@ package org.springframework.cache.concurrent; @@ -19,7 +19,6 @@ package org.springframework.cache.concurrent;
import org.junit.jupiter.api.Test;
import org.springframework.cache.Cache;
import org.springframework.cache.CacheManager;
import static org.assertj.core.api.Assertions.assertThat;
@ -31,7 +30,7 @@ class ConcurrentMapCacheManagerTests { @@ -31,7 +30,7 @@ class ConcurrentMapCacheManagerTests {
@Test
void testDynamicMode() {
CacheManager cm = new ConcurrentMapCacheManager();
ConcurrentMapCacheManager cm = new ConcurrentMapCacheManager();
Cache cache1 = cm.getCache("c1");
assertThat(cache1).isInstanceOf(ConcurrentMapCache.class);
Cache cache1again = cm.getCache("c1");
@ -65,6 +64,14 @@ class ConcurrentMapCacheManagerTests { @@ -65,6 +64,14 @@ class ConcurrentMapCacheManagerTests {
assertThat(cache1.get("key3").get()).isNull();
cache1.evict("key3");
assertThat(cache1.get("key3")).isNull();
cm.removeCache("c1");
assertThat(cm.getCache("c1")).isNotSameAs(cache1);
assertThat(cm.getCache("c2")).isSameAs(cache2);
cm.resetCaches();
assertThat(cm.getCache("c1")).isNotSameAs(cache1);
assertThat(cm.getCache("c2")).isNotSameAs(cache2);
}
@Test
@ -107,11 +114,24 @@ class ConcurrentMapCacheManagerTests { @@ -107,11 +114,24 @@ class ConcurrentMapCacheManagerTests {
cm.setAllowNullValues(true);
Cache cache1y = cm.getCache("c1");
Cache cache2y = cm.getCache("c2");
cache1y.put("key3", null);
assertThat(cache1y.get("key3").get()).isNull();
cache1y.evict("key3");
assertThat(cache1y.get("key3")).isNull();
cache2y.put("key4", "value4");
assertThat(cache2y.get("key4").get()).isEqualTo("value4");
cm.removeCache("c1");
assertThat(cm.getCache("c1")).isNull();
assertThat(cm.getCache("c2")).isSameAs(cache2y);
assertThat(cache2y.get("key4").get()).isEqualTo("value4");
cm.resetCaches();
assertThat(cm.getCache("c1")).isNull();
assertThat(cm.getCache("c2")).isSameAs(cache2y);
assertThat(cache2y.get("key4")).isNull();
}
@Test

Loading…
Cancel
Save