将两个Mono合并在一起,其中第二个Mono订阅了第一个Mono

问题描述 投票:0回答:1

我最近一直在使用带有Spring框架的Java中的反应堆库来学习反应式编程,在大多数情况下,我已经掌握了它。但是,我已经几次遇到相同的情况,并且想对我要去哪里做一些建议。

我一直在苦苦挣扎的要点通常是我想对单声道做一些事情,例如找到一些补充数据,然后将其添加回原始的单声道。 zip函数对我来说似乎是理想的候选者,但是我最终两次订阅了原始的mono,这不是我的意图。

这是我一直试图解决的情况类型的一个人为设计的示例,因为我无法共享我的公司代码。假设我们正在使用反应式数据库并设置了记录器,并且Person类是不可变的,但具有with 方法。

public Mono<Person> getPersonWithFamilyMembers(Integer id){
    log.info("Finding person with id {}", id);

    personRepository.findById(id)
        .switchIfEmpty(Mono.error(NotFoundException::new))
        .doOnNext(person -> log.info("Found person: {}", person))
        .as(this::fetchAndAddFamilyMembers)
        .doOnSuccess(person -> log.info("Successfully found person with family members"));
}

private Mono<Person> fetchAndAddFamilyMembers(Mono<Person> personMono){
    Mono<List<Person>> familyMembersMono = personMono
        .map(Person::getFamilyId)
        .flatMapMany(PersonRepository::findByFamilyId)
        .collectList();

    return personMono.zipWith(familyMembersMono, Person::withFamilyMembers);
}

运行这样的代码时看到的输出是:

INFO | Finding person with id 1
INFO | Found person: Person(id=1, familyId=1, familyMembers=[])
INFO | Found person: Person(id=1, familyId=1, familyMembers=[])
INFO | Successfully found person with family members

这确实很有意义,因为原始人单声道已经在两个地方订阅了,我将其映射到familyMembersMono,当我将它们压缩在一起时,但是如果我不想对存储库进行不必要的调用,可以避免。

有人建议使用更好的方法来处理这种行为吗?

java project-reactor spring-reactive zipwith spring-reactor
1个回答
1
投票

通常,您不是将数据“添加”到Mono,而是将其中的数据“添加”。考虑到这一点,请使用flatMap而不是as

public Mono<Person> getPersonWithFamilyMembers(Integer id){
    log.info("Finding person with id {}", id);

    return personRepository.findById(id)
        .switchIfEmpty(Mono.error(NotFoundException::new))
        .doOnNext(person -> log.info("Found person: {}", person))
        .flatMap(this::fetchAndAddFamilyMembers)
        .doOnSuccess(person -> log.info("Successfully found person with family members"));
}

private Mono<Person> fetchAndAddFamilyMembers(Person person){ // this accepts Person, not Mono<Person>
    return personRepository.findByFamilyId(person.getFamilyId())
        .collectList()
        .map(person::withFamilyMembers);
}
© www.soinside.com 2019 - 2024. All rights reserved.