将多个被动发布者/ Flux / Mono对象组合成阻止请求

时间:2017-07-28 19:56:28

标签: redis reactive-programming project-reactor lettuce

我对被动的世界非常陌生,并努力了解如何完成任务。我正在处理遗留项目,我必须实现一个接口,该接口有许多方法可以从redis查询各种对象。有时查询就像通过ID查询哈希一样简单,因此只需调用redis来获取哈希值。其他时候,我可能需要首先根据某些参数从redis集中查找ID,然后使用结果ID获取哈希值。我在Spring Boot应用程序中使用Reactor 3.1.0.M3和Lettuce 5.0.0.RC1。

我对这两个示例方法的现有代码如下所示:

    public <T extends CatalogInfo> T get(String id, Class<T> clazz) {
        String result = (String)repository.getRedisHashRepository().getHashById(CatalogUtils.root(clazz).getSimpleName(), id);
        if (null != result) {
            return serializer.fromData(result, clazz);
        }
        return null;

    }

    public <T extends CatalogInfo> T get(String attName, String attValue, Class<T> clazz) {

        String attKey = CatalogUtils.buildKey(CatalogUtils.root(clazz), attName, attValue);

        String id = CatalogUtils.getIdFromSet(repository.getRedisSetRepository().getSetMembers(attKey));
        if (id == null) {
            return null;
        }
        return get(id, clazz);
    }

其中有一些实用程序函数可以帮助我构建我想要从类名中使用redis的键,并确保存储在redis集中的ID是单个值。如您所见,在第二个get方法中,我使用set中的结果调用第一个get方法。

使用Lettuce / Reactor实现第一个方法很简单:

public <T extends CatalogInfo> Mono<String> getReactive(String id, Class<T> clazz, Publisher<String>... publisher) {
    Mono<String> mono = Mono.just(id).flatMap(new Function<String, Mono<String>>() {
        @Override
        public Mono<String> apply(String id) {
            return hashCommands.hget(CatalogUtils.root(clazz).getSimpleName(), id);
        }
    });
    return mono;
}

此时,我可以调用mono.block()来获取结果值。通过将两个flatMaps /函数链接在一起,我可以相当容易地获得第二个get方法的功能:

public <T extends CatalogInfo> Flux<String> getIdFromSetReactive(String attName, String attValue, Class<T> clazz) {
    String attKey = CatalogUtils.buildKey(CatalogUtils.root(clazz), attName, attValue);

    Flux<String> flux = Flux.just(attKey).flatMap(new Function<String, Flux<String>>() {
        @Override
        public Flux<String> apply(String attKey) {
            return commands.smembers(attKey);
        }
    }).flatMap(new Function<String, Publisher<String>>() {
        @Override
        public Publisher<String> apply(String id) {
            return hashCommands.hget(CatalogUtils.root(clazz).getSimpleName(), id);
        }
    });
    return flux;
} 

我有许多不同类型的方法,可能需要最多8次调用才能完成redis。在我的原始代码中,我可以重复使用每种方法并从另一种方法中调用一种方法,但我无法弄清楚如何使用reactor来实现这一点。

我希望能够调用一个构建Flux的方法来从redis集中获取ID(让它称之为fluxA),然后调用另一个构建Flux的方法来查询基于redis的哈希值在ID(fluxB)等

我可能需要将我可能需要的每个函数定义为这样的成员变量:

private Function<String, Flux<String>> getIdFromSetFunction = new Function<String, Flux<String>>() {
        @Override
        public Flux<String> apply(String attKey) {
            return commands.smembers(attKey);
        }
    }; 

然后拨打电话

return Flux.just(attKey).flatMap(getIdFromSetFunction).flatMap(getHash);

唯一的问题是在这些函数中执行的代码需要我的方法调用中当前可用的Class信息。但我不确定这是正确的方法。

非常感谢任何建议!

1 个答案:

答案 0 :(得分:2)

从概念上讲,你并不是在构建单一对象&#34;和#34;为每一步创造一个新的&#34;。

Mono<String> a = Mono.just("something");
Mono<String> b = a.flatMap( s -> goDoSomethingElseThatReturnsAMono(s));

String result = b.block();

你可以随心所欲地保持链接。 (如果您想要单独处理多个数据项,请使用Flux进入Mono.flatMapMany世界。

在调用block之前没有任何反应,因为它订阅b并阻止当​​前线程,直到结果可用。