我需要缓存来自ReactiveMongoRepository的数据。数据大约每年更新两次,所以我不在乎缓存是否过期。

由于我们用通量can't use @Cacheable,因此我想找到一种简单易行的方法来存储从Mongo到Redis的数据,并使用该数据(如果存在),否则将其存储并提供原始数据。

有没有比这更直接的方法

  @GetMapping
  public Flux<AvailableInspection> getAvailableInspectionsRedis() {
    AtomicInteger ad = new AtomicInteger();
    return availableInspectionReactiveRedisOperations.opsForZSet().range("availableInspections", Range.<Long>from(Range.Bound.inclusive(0L)).to(Range.Bound.inclusive(-1L)))
        .switchIfEmpty(availableInspectionMongoRepository.findAll().map(e -> {
          availableInspectionReactiveRedisOperations.opsForZSet().add("availableInspections", e, ad.getAndIncrement()).block();
          return e;
        }));
  }

我正在寻找的是一个可以让我像@Cacheable注解一样缓存数据的选项。我正在寻找一种通用的解决方案,以能够缓存任何类型的流量。

最佳答案

我怀疑是否存在针对该问题的现成解决方案。
但是,您可以轻松构建自己的接口(interface)来获取通用的缓存对象并将其加载到缓存中:

public interface GetCachedOrLoad<T> {

  Flux<T> getCachedOrLoad(String key, Flux<T> loader, Class<? extends T> clazz);
}

每个需要此功能的类都将通过构造函数注入(inject)它,并按如下方式使用它:
public class PersistedObjectRepository {

  private final GetCachedOrLoad<PersistedObject> getCachedOrLoad;

  public PersistedObjectRepository(final GetCachedOrLoad<PersistedObject> getCachedOrLoad) {
    this.getCachedOrLoad = getCachedOrLoad;
  }

  public Flux<PersistedObject> queryPersistedObject(final String key) {
    return getCachedOrLoad.getCachedOrLoad(key, queryMongoDB(key), PersistedObject.class);
  }

  private Flux<PersistedObject> queryMongoDB(String key) {
    // use reactivemongo api to retrieve Flux<PersistedObject>
  }
}

然后,您需要创建一个实现GetCachedOrLoad<T>的对象,并将其用于依赖项注入(inject)。
public class RedisCache<T> implements GetCachedOrLoad<T> {

  private final Function<String, Flux<String>> getFromCache;
  private final BiConsumer<String, String> loadToCache;
  private final Gson gson;

  public RedisCache(Gson gson, RedisReactiveCommands<String, String> redisCommands) {
    this.getFromCache = key -> redisCommands.lrange(key, 0, -1);
    this.loadToCache = redisCommands::lpush;
    this.gson = gson;
  }

  @Override
  public Flux<T> getCachedOrLoad(final String key, Flux<T> loader, Class<? extends T> clazz) {
    final Flux<T> cacheResults = getFromCache.apply(key)
      .map(json -> gson.fromJson(json, clazz));
    return cacheResults.switchIfEmpty(
      loader.doOnNext(value -> loadToCache.accept(key, gson.toJson(value))));
  }
}

希望这足够通用:)。
PS。这不是生产就绪的实现,需要针对您自己的需求进行调整,例如添加异常处理,自定义json序列化等。

关于java - 用Spring Webflux替代@Cacheable,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/52871436/

10-14 15:28
查看更多