所有 Spring Cache 注释(即@Cacheable
,@CacheEvict
等)在每个操作上都作用于 1 个缓存条目。 @CacheEvict
确实支持清除整个缓存(使用allEntries
属性,但在这种情况下会忽略键),但它在您所描述的单个操作中基于键模式清除部分条目集时没有选择性(能够)。
这背后的主要原因是 Spring Cache接口抽象本身,其中evict(key:Object)方法采用单个键参数。但从技术上讲,它实际上取决于底层的 Cache 实现(例如GemfireCache),它需要支持对所有键匹配特定模式的条目进行驱逐,这通常不是大多数缓存的情况(例如,GemFire 肯定不是,并且也不适用于 Google Guava Cache;请参见此处和此处。)
这并不是说你绝对不能实现你的目标。这不是开箱即用的支持。
有趣的是,减去你的方法的一些技术问题,你的条件达到了你想要的......只有当密钥满足条件时才会发生缓存驱逐。但是,您 @CacheEvict 注释的方法只是缺少“键”,因此出现错误。所以,像下面这样的东西会满足你的条件下的SpEL......
@CacheEvict(condition = "#key.startsWith('abc')")
public void someMethod(String key) {
...
}
但是,在这种情况下,您必须将键指定为参数。但是,你不想要一个特定的键,你想要一个匹配多个键的模式。因此,放弃条件并使用...
@CacheEvict
public void someMethod(String keyPattern) {
...
}
例如,使用 Guava 作为缓存提供程序,您现在需要提供扩展GuavaCache的“自定义”实现。
public class CustomGuavaCache extends org.springframework.cache.guava.GuavaCache {
protected boolean isMatch(String key, String pattern) {
...
}
protected boolean isPattern(String key) {
...
}
@Override
public void evict(Object key) {
if (key instanceof String && isPattern(key.toString()))) {
Map<String, Object> entries = this.cache.asMap();
Set<String> matchingKeys = new HashSet<>(entries.size());
for (String actualKey : entries.keySet()) {
if (isMatch(actualKey, key.toString()) {
matchingKeys.add(actualKey);
}
}
this.cache.invalidateAll(matchingKeys);
}
else {
this.cache.invalidate(key);
}
}
}
现在只需扩展GuavaCacheManager以插入您的“自定义” GuavaCache
(CustomGuavaCache
)...
public class CustomGuavaCacheManager extends org.springframework.cache.guava.GuavaCacheManager {
@Override
protected Cache createGuavaCache(String name) {
return new CustomGuavaCache(name, createNativeGuavaCache(name), isAllowNullValues());
}
}
这种方法利用了 Guava 的Cache 的 invalidateAll(keys:Iterable)方法。而且,当然,您可以使用 Java 的 Regex 支持对要在方法内逐出的所需键执行“匹配” isMatch(key, pattern)
。
所以,我没有测试过这个,但是这个(或类似的东西)应该(几乎)实现你想要的(手指交叉;-)
希望这可以帮助!
干杯,约翰