调用第二个Mono而不丢失第一个结果的最佳方法是什么?

时间:2018-11-14 07:53:40

标签: java spring-webflux project-reactor

我有需要与两个反应性依赖项交互的代码-保存到数据库并发布到流,每个都返回Mono实例。之后,我需要做更多的处理-全部使用开始的原始对象,如下所示:

val myObject = Mono.just(“thing”);
myObject.flatMap(repository::save)
        .flatMap(stream::publish)
        .map(obj -> moreProcessing(obj));

但是问题是,repository.save不会返回我感兴趣的对象的Monostream.publish也不会返回。

我可以通过以下方式实现我想要的东西:

myObject.flatMap(obj -> repository.save(obj).then(Mono.just(obj))
        .flatMap(obj -> stream.publish(obj).then(Mono.just(obj))
        .map(obj -> moreProcessing(obj));

即映射到依赖函数只是为了获得其行为,然后再次直接映射,但这似乎很奇怪-就像我可能会缺少一些更好的使用API​​的方法,这种方法并没有提示我在类型之间进行映射,因为实际上,这不是我使用的flatMap

我还可以使用类似的东西:

myObject.flatMap(obj ->
            repository.save(obj)
                .flatMap(x -> publisher.stream(obj))
                .map(x -> moreProcessing(obj)));

但这也不是一个好方法,因为即使在相对简单的情况下,它也会导致难以维护的代码。

有想法吗?

3 个答案:

答案 0 :(得分:0)

我有一个类似的问题,我使用下面的代码解决了。我认为重要的是不要不惜一切代价迷失方法链。过度挑战很容易创建难以阅读的结构。

@Test
public void mergeMonos(){
    Mono<String> myObject = Mono.just("my object");
    Mono<String> savedToDB = saveToDb(myObject);
    Mono<String> savedToStream = saveToStream(myObject);


    //if you need to wait for the first two to complete
    Flux.concat(savedToDB, savedToStream, myObject)
            .last()
            .subscribe(System.out::println);

    //if you don't need to wait for the db and stream
    Flux.merge(savedToDB, savedToStream, myObject)
            .last()
            .subscribe(System.out::println);
}

private Mono<String> saveToStream(Mono<String> myObject) {
    return myObject.map(t-> "saved to stream");
}

private Mono<String> saveToDb(Mono<String> myObject) {
    return myObject.map(t-> "saved to db");
}

答案 1 :(得分:0)

您尝试过thipWhen吗?如果rightGenerator的结果为空(没有下一个信号),它的行为就像您希望的那样,有唯一的限制,它立即完成。因此,您需要返回Optional或使用thenReturnswitchIfEmpty

答案 2 :(得分:0)

避免丢失任何参考文献的一种方法可能是:

Mono<User> monoUser = userRepository.findByUsername(username)
                                .filter(u -> validatePassword(pass, u.getPassword()));

Mono<Clinic> monoClinic = monoUser.flatMap(u -> clinicRepository.findByUserId(u.getId()));
        
return Mono.zip(monoUser, monoClinic, (u,c) -> proccess(u, c)); 

第一个 Mono 返回一个用户,第二个 Mono 使用第一个 Mono 返回的用户并返回一个诊所,返回的 Mono(第三个 Mono)使用第一个 Mono 的输出和第二个 Mono 的输出创建一个不同的对象(由使用用户和诊所的过程方法返回)