代码之家  ›  专栏  ›  技术社区  ›  baao

使用springwebflux替代@Cacheable

  •  10
  • baao  · 技术社区  · 7 年前

    我需要缓存来自 ReactiveMongoRepository

    自从我们 can't use @Cacheable 有了flux,我想找到一种简单明了的方法来存储从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注释那样缓存数据。我正在寻找一个通用的解决方案,能够缓存任何类型的流量。

    1 回复  |  直到 7 年前
        1
  •  7
  •   Ilya Zinkovich    7 年前

    我怀疑这个问题是否有现成的解决办法。 但是,您可以轻松构建自己的接口,以获取通用缓存对象并将其加载到缓存:

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

    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> 并使其可用于依赖注入。

    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))));
      }
    }
    

    希望这足够通用:)。