具有复杂条件逐出的缓存
Cache With Complex Conditional Eviction
我正在尝试使用 caffeine
和 spring-boot-starter-cache
来实现以下缓存逻辑:
- 如果到期时间已经过了和条件(需要计算和I/O)被评估为 TRUE 然后强制获取数据并更新缓存。
- 如果到期时间已经过了和条件(需要计算和I/O)被评估为 FALSE 然后不要使缓存数据无效并从缓存中检索值。
- 如果过期时间 未 已过,则从缓存中检索值。
我按照这个指南工作:
https://www.baeldung.com/spring-boot-caffeine-cache
我在缓存对象的 getter
方法上尝试了各种使用 @CachePut
、@CacheEvict
和 @Cacheable
的方法,但核心问题是我需要用过期时间和另一个逻辑来调节驱逐,但这些注释无法控制是否驱逐……也许这可以使用 Scheduler
?
来完成
您似乎没有使用咖啡因作为缓存系统。
在这种情况下,使用自定义 class 并在简单的 Map 中保存数据会更好,因为它为您提供了更大的灵活性。
这是骨架
public class SpecialCache {
private Map<String, SpecialCache.Entry> map = new HashMap<>();
private boolean specialCondition(String key) {
...
}
private Object fetch(String key) {
...
}
public Object get(String key) {
SpecialCache.Entry entry = map.get(key);
if (entry.getExpiringEpoch() > System.currentTimeMillis()) {
if (specialCondition(key)) {
Object data = fetch(key);
entry.setExpiringEpoch(...);
entry.setData(data);
return data;
} else {
return entry.getData();
}
} else {
return entry.getData();
}
}
@Data
public static class Entry {
private long expiringEpoch;
private Object data;
}
}
在示例中,我在缓存中添加了 specialCondition 和 fetch 方法。您还可以将这些方法作为 lambda 函数传递给 get 方法,以获得更大的灵活性。
代码必须填写,例如您需要添加:
- 检查缓存中不存在的键
- 填充缓存的方法(放置?)
我认为您正在寻找 refreshAfterWrite
并覆盖 CacheLoader.reload(K, V)
。
这是解释细节的post:https://github.com/ben-manes/caffeine/wiki/Refresh
您的案例的实施类似于:
@Log4j2
@Configuration
public class CacheConfig {
@Bean
public Cache<String,Item> caffeineConfig() {
return Caffeine.newBuilder()
.refreshAfterWrite(10, TimeUnit.SECONDS)
.build(new ConditionalCacheLoader<>(this::shouldReload, this::load));
}
private Item load(String key){
//load the item
return null;
}
private boolean shouldReload(Item oldValue){
//your condition logic here
return true;
}
private static class Item{
// the item value can contain any data
}
private static class ConditionalCacheLoader<K,V> implements CacheLoader<K,V>{
private final Predicate<V> shouldReload;
private final Function<K,V> load;
protected ConditionalCacheLoader(Predicate<V> shouldReload, Function<K, V> load) {
this.shouldReload = shouldReload;
this.load = load;
}
@Override
public V load(K key) throws Exception{
return load.apply(key);
}
@Override
public V reload(K key, V oldValue) throws Exception {
if (shouldReload.test(oldValue)){
return load(key);
}else {
return oldValue;
}
}
}
}
我正在尝试使用 caffeine
和 spring-boot-starter-cache
来实现以下缓存逻辑:
- 如果到期时间已经过了和条件(需要计算和I/O)被评估为 TRUE 然后强制获取数据并更新缓存。
- 如果到期时间已经过了和条件(需要计算和I/O)被评估为 FALSE 然后不要使缓存数据无效并从缓存中检索值。
- 如果过期时间 未 已过,则从缓存中检索值。
我按照这个指南工作: https://www.baeldung.com/spring-boot-caffeine-cache
我在缓存对象的 getter
方法上尝试了各种使用 @CachePut
、@CacheEvict
和 @Cacheable
的方法,但核心问题是我需要用过期时间和另一个逻辑来调节驱逐,但这些注释无法控制是否驱逐……也许这可以使用 Scheduler
?
您似乎没有使用咖啡因作为缓存系统。
在这种情况下,使用自定义 class 并在简单的 Map 中保存数据会更好,因为它为您提供了更大的灵活性。
这是骨架
public class SpecialCache {
private Map<String, SpecialCache.Entry> map = new HashMap<>();
private boolean specialCondition(String key) {
...
}
private Object fetch(String key) {
...
}
public Object get(String key) {
SpecialCache.Entry entry = map.get(key);
if (entry.getExpiringEpoch() > System.currentTimeMillis()) {
if (specialCondition(key)) {
Object data = fetch(key);
entry.setExpiringEpoch(...);
entry.setData(data);
return data;
} else {
return entry.getData();
}
} else {
return entry.getData();
}
}
@Data
public static class Entry {
private long expiringEpoch;
private Object data;
}
}
在示例中,我在缓存中添加了 specialCondition 和 fetch 方法。您还可以将这些方法作为 lambda 函数传递给 get 方法,以获得更大的灵活性。
代码必须填写,例如您需要添加:
- 检查缓存中不存在的键
- 填充缓存的方法(放置?)
我认为您正在寻找 refreshAfterWrite
并覆盖 CacheLoader.reload(K, V)
。
这是解释细节的post:https://github.com/ben-manes/caffeine/wiki/Refresh
您的案例的实施类似于:
@Log4j2
@Configuration
public class CacheConfig {
@Bean
public Cache<String,Item> caffeineConfig() {
return Caffeine.newBuilder()
.refreshAfterWrite(10, TimeUnit.SECONDS)
.build(new ConditionalCacheLoader<>(this::shouldReload, this::load));
}
private Item load(String key){
//load the item
return null;
}
private boolean shouldReload(Item oldValue){
//your condition logic here
return true;
}
private static class Item{
// the item value can contain any data
}
private static class ConditionalCacheLoader<K,V> implements CacheLoader<K,V>{
private final Predicate<V> shouldReload;
private final Function<K,V> load;
protected ConditionalCacheLoader(Predicate<V> shouldReload, Function<K, V> load) {
this.shouldReload = shouldReload;
this.load = load;
}
@Override
public V load(K key) throws Exception{
return load.apply(key);
}
@Override
public V reload(K key, V oldValue) throws Exception {
if (shouldReload.test(oldValue)){
return load(key);
}else {
return oldValue;
}
}
}
}