Scatter-gather:组合Mono <list <item>&gt;组合单个Mono <list <item>&gt;

时间:2018-01-25 20:38:44

标签: java spring reactive-programming java-9 spring-webflux

我可以将Mono<List<Item>>个数据源列表合并到一个包含所有项目的Mono<List<Item>>中,而不会阻止吗?

在我的带有Lombok分散 - 收集应用程序的JDK 9 Spring Boot 2中,这个阻止版本有效:

    private Mono<List<Item>> gather(List<Mono<List<Item>>> data) {
        return Mono.just( data.stream().map(m -> m.block())
                .flatMap(List::parallelStream).collect(Collectors.toList()));
    }

每个源数据流在其block()上调用Mono;如果可能的话,我想减少block()次呼叫...最好是零。有什么想法吗?

测试用例

@RunWith(SpringRunner.class)
public class ReactiveTests {
    @Test
    public void testScatterGather() {
        List<List<Item>> dataSet = dataSet();
        Mono<List<Item>> data = gather(scatter(dataSet));
        StepVerifier.create(data)
            .expectNext(toItemList(dataSet))
            .expectComplete();
    }

    private Mono<List<Item>> gather(List<Mono<List<Item>>> data) {
        return Mono.just( data.stream().map(m -> m.block())
                .flatMap(List::parallelStream).collect(Collectors.toList()));
    }

    private List<Mono<List<Item>>> scatter(List<List<Item>> data) {
        return newMonoLists(data);
    }

    private List<Item> toItemList(List<List<Item>> data) {
        return data.stream().flatMap(List::stream).collect(Collectors.toList());
    }

    private List<Mono<List<Item>>> newMonoLists(List<List<Item>> data) {
        return data.stream().map(l -> Mono.just(l)).collect(Collectors.toList());
    }

    private List<List<Item>> dataSet() {
        return Arrays.asList(dataSet(1L),dataSet(4L),dataSet(7L));
    }

    private List<Item> dataSet(long id) {
        return Arrays.asList(new Item(id), new Item(id+1), new Item(id+2));
    }
    @Data @AllArgsConstructor private static class Item { private Long id; }
}

1 个答案:

答案 0 :(得分:1)

假设您有2个具有字符串列表的Mono源。

Mono<List<String>> listMono1 = Mono.just(Arrays.asList("1","3","5","7","9","11"));
Mono<List<String>> listMono2 = Mono.just(Arrays.asList("2","4","6","8","10","12"));

您可以使用方法Flux.merge()合并两个发布商,该方法接收一堆发布商并将它们合并在一起。

但如果您合并下面的发布商,那么它最终会给您List<List<String>>,这是您不想要的。

Flux.merge(listMono1, listMono2).collectList();

因此,您必须修改listMono1和listMono2,以便它们发出List的各个元素,然后合并它们。为此,您可以使用Mono.flatMapMany()来帮助您从List中发出所有元素。所以,最后你将获得如下组合List:

Flux.merge(listMono1.flatMapMany(Flux::fromIterable),listMono2.flatMapMany(Flux::fromIterable)).collectList();

希望最终得到你想要的东西!