如果缓存刷新失败,我需要使用旧的/陈旧的缓存值。 我浏览了互联网上的许多示例并决定尝试使用咖啡因缓存来实现此要求(更具体地说是使用 refreshAfterWrite 功能)。我能够使用咖啡因缓存数据,但在缓存刷新(rest api 失败)失败时无法获取旧/陈旧值。 我用过 SimpleCacheManager(org.springframework.cache.support.SimpleCacheManager) 和 CaffeineCache。
**simpleCacheManager bean code** :
<bean id="simpleCacheManager" class="org.springframework.cache.support.SimpleCacheManager">
<property name="caches" ref="caffeineCaches" />
</bean>
**caffeine cache** :
@Bean
public Collection<? extends org.springframework.cache.Cache> caffeineCaches(){
Collection<CaffeineCache> caffeineCaches = new ArrayList<>();
caffeineCaches.add(new CaffeineCache("pbdBankRegistry",
Caffeine.newBuilder()
.refreshAfterWrite(2, TimeUnit.MINUTES)
.initialCapacity(1)
.maximumSize(2)
.recordStats()
.build(new CustomCacheLoader()),false));
return caffeineCaches;
}
**CacheLoader Code :**
public class CustomCacheLoader implements CacheLoader<Object, Object> {
@Nullable
@Override
public Object load(Object o) throws Exception {
return null;
}
@Override
public Map loadAll(Set keys) throws Exception {
return CacheLoader.super.loadAll(keys);
}
@Override
public CompletableFuture asyncLoad(Object key, Executor executor) throws Exception {
return CacheLoader.super.asyncLoad(key, executor);
}
@Override
public CompletableFuture<? extends Map> asyncLoadAll(Set keys, Executor executor) throws Exception {
return CacheLoader.super.asyncLoadAll(keys, executor);
}
@Nullable
@Override
public Object reload(Object key, Object oldValue) throws Exception {
return CacheLoader.super.reload(key, oldValue);
}
@Override
public CompletableFuture asyncReload(Object key, Object oldValue, Executor executor) throws Exception {
return CacheLoader.super.asyncReload(key, oldValue, executor);
}
我想我必须从重新加载方法或 Caffeine 的构建方法调用我的 api。但我不确定。我是缓存的新手,所以这里需要你的帮助来实现这段代码。
注意:我的应用程序是 spring 4.3.3.RELEASE 版本。
在类似的情况下,类似下面的内容对我有用:根据
https://github.com/ben-manes/caffeine/wiki/Refresh上的示例,不是向
.build
提供函数,而是传入一个实现CacheLoader
的对象,并覆盖load
和reload
方法。
/**
* @see https://www.javadoc.io/doc/com.github.ben-manes.caffeine/caffeine/latest/com.github.benmanes.caffeine/com/github/benmanes/caffeine/cache/CacheLoader.html#reload(K,V)
*/
class CacheLoader_keepOldIf<K,V> implements CacheLoader<K,V> {
private Function<K,V> loadFn;
private Function<V,Boolean> testNewFn;
CacheLoader_keepOldIf(Function<V,Boolean> testNewFn, Function<K,V> loadFn
){
this.loadFn = loadFn;
this.testNewFn = testNewFn;
}
@Override
public @Nullable V reload(K key, V oldValue) throws Exception {
V newValue = loadFn.apply(key);
return testNewFn.apply(newValue) ? oldValue : newValue;
}
@Override
public @Nullable V load(K key) throws Exception {
return loadFn.apply(key);
}
}
LoadingCache<String, Object> myCache = Caffeine.newBuilder()
.refreshAfterWrite(5, TimeUnit.SECONDS)
.build(new CacheLoader_keepOldIf<String,Object>(
newValue -> newValue==null,
key -> someExpensiveCallReturningNullOnFailure()
))
;
这段代码似乎不必要地冗长只是为了覆盖
reload
方法:其中一些无疑是我的错,还有一些可能是 Java 的错。但它完成了工作:如果我的数据库调用失败,它返回 null,并使用以前缓存的值。大概也可以在 load
方法中指定一个默认值,以防第一次调用填充缓存失败。
(根据 Ben Manes 对问题的评论,我认为问题示例中
load
的覆盖应该返回某些内容而不是 null 以解决原始问题)。