关于Project Reactor的flatMap中的线程的困惑

时间:2019-08-11 14:40:32

标签: java spring spring-boot spring-webflux project-reactor

我正在玩Project Reactor和反应式MongoDB存储库。我有以下代码:

@Builder
@FieldDefaults(level = AccessLevel.PRIVATE)
@Getter
@Setter
@AllArgsConstructor
@NoArgsConstructor
@ToString
@Document
public class Person {
    @Id
    Integer id;
    String name;
}
public interface ReactivePersonRepository extends ReactiveCrudRepository<Person, Integer> {
}

和主要的@SpringBootApplication类:

@SpringBootApplication
@EnableReactiveMongoRepositories
@RequiredArgsConstructor
public class ReactiveDatabaseApplication {

    private final ReactivePersonRepository reactivePersonRepository;

    public static void main(String[] args) {
        SpringApplication.run(ReactiveDatabaseApplication.class, args);
    }

    @PostConstruct
    public void postConstruct() {
        Scheduler single = Schedulers.newSingle("single-scheduler");
        IntStream.range(0, 10).forEach(i ->
                Flux.just(Person.builder()
                        .id(i)
                        .name("PersonName")
                        .build())
                        .flatMap(personToSave -> {
                            System.out.println(String.format(
                                    "Saving person from thread %s", Thread.currentThread().getName()));
                            return reactivePersonRepository.save(personToSave);
                        })
                        //.publishOn(single)
                        .flatMap(savedPerson -> {
                            System.out.println(String.format(
                                    "Finding person from thread %s", Thread.currentThread().getName()));
                            return reactivePersonRepository.findById(savedPerson.getId());
                        })
                        //.publishOn(single)
                        .flatMap(foundPerson -> {
                            System.out.println(String.format(
                                    "Deleting person from thread %s", Thread.currentThread().getName()));
                            return reactivePersonRepository.deleteById(foundPerson.getId());
                        })
                        //.publishOn(single)
                        .subscribeOn(single)
                        .subscribe(aVoid -> System.out.println(String.format(
                                "Subscription from thread %s", Thread.currentThread().getName()))));
    }
}

Flux::subscribeOn方法说明说:

  

因此,将此运算符放置在链中的任何位置也会影响   来自的onNext / onError / onComplete信号的执行*上下文   链的起点,直到*下一次出现{@link   publishOn(Scheduler)publishOn}

这让我有些困惑,因为当我在处理链中没有指定任何publishOn时,线程名称的打印值是:

  

从线程单调度程序1中拯救人员-符合预期

     

从线程-13查找人

     

从线程Thread-6查找人

     

从线程-15查找人

     

从线程Thread-6中删除人

     

从线程Thread-5中删除人员

     

从线程Thread-4中删除人员

我不明白为什么。 subscribeOn方法中指定的调度程序是否应该用于每次flatMap执行?

当我取消注释publishOn行时,一切都由给定的单个调度程序执行,这与预期的一样。

谁能解释为什么没有flatMappublishOn操作不使用单个调度程序?

1 个答案:

答案 0 :(得分:1)

这个人为的例子可能更清楚:

Scheduler single = Schedulers.newSingle("single-scheduler");
Flux.just("Bob")
        .flatMap(x -> {
            System.out.println(String.format(
                    "Saving person from thread %s", Thread.currentThread().getName()));
            return Mono.just(x).publishOn(Schedulers.elastic());
        })
        .flatMap(x -> {
            System.out.println(String.format(
                    "Finding person from thread %s", Thread.currentThread().getName()));
            return Mono.just(x).publishOn(Schedulers.elastic());
        })
        .flatMap(x -> {
            System.out.println(String.format(
                    "Deleting person from thread %s", Thread.currentThread().getName()));
            return Mono.just(x).publishOn(Schedulers.elastic());
        })
        .subscribeOn(single)
        .subscribe(aVoid -> System.out.println(String.format(
        "Subscription from thread %s", Thread.currentThread().getName())));

哪个会给出类似的内容:

Saving person from thread single-scheduler-1
Finding person from thread elastic-2
Deleting person from thread elastic-3
Subscription from thread elastic-4

或者,换句话说,您的反应式存储库不在同一调度程序上发布,并且是您看到行为的原因。 “直到下一次出现publishOn()时,这并不意味着下次您的代码调用publishOn(),它也可以位于您的{ {1}}个电话,您将无法控制。