2

我正在尝试使用caffeinespring-boot-starter-cache实现以下缓存逻辑:

  1. 如果过期时间已经过去并且条件(需要计算和 I/O)被评估为 TRUE,则强制获取数据并更新缓存。
  2. 如果过期时间已经过去并且条件(需要计算和 I/O)被评估为 FALSE,那么不要使缓存数据无效并从缓存中检索值。
  3. 如果到期时间尚未过去则从缓存中检索值。

我按照本指南工作: https ://www.baeldung.com/spring-boot-caffeine-cache

我尝试了各种方法,使用@CachePut,@CacheEvict和我正在缓存的对象@Cacheablegetter方法,但核心问题是我需要用过期时间和另一个逻辑来限制驱逐,但是这些注释无法控制是否驱逐。 ..也许这可以使用Scheduler?

4

2 回答 2

1

您似乎没有使用咖啡因作为缓存系统。

在这种情况下,使用自定义类并在简单的 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 方法以获得更大的灵活性。

代码必须完成,例如您需要添加:

  • 检查缓存中不存在的键
  • 填充缓存的方法(放置?)
于 2021-08-12T14:51:36.587 回答
1

我认为您正在寻找refreshAfterWrite并覆盖CacheLoader.reload(K, V). 这是解释细节的帖子: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;
            }
        }
    }
}
于 2021-08-13T17:25:54.463 回答