【问题标题】:Alternatives to @Cacheable with spring webflux使用 spring webflux 替代 @Cacheable
【发布时间】:2019-03-23 02:38:51
【问题描述】:

我需要缓存来自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 批注一样。我正在寻找一种能够缓存任何类型通量的通用解决方案。

【问题讨论】:

    标签: java spring spring-webflux


    【解决方案1】:

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

    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&lt;T&gt; 的对象并使其可用于依赖注入。

    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 序列化等等。

    【讨论】:

      猜你喜欢
      • 2019-12-02
      • 1970-01-01
      • 2018-06-17
      • 2015-11-26
      • 2018-02-02
      • 2019-12-07
      • 1970-01-01
      • 1970-01-01
      • 2012-12-25
      相关资源
      最近更新 更多