Spring Webflux的新手警报(v 2.0.1.RELEASE)。
我希望将Spring Webflux用于后端(Webless)应用程序,以便从JMS侦听器处理大量数据。
我的理解是Spring Webflux提供了一种非阻塞/异步并发模型。但是,我得到了一个基本问题,我需要一些帮助。作为一个免责声明,这个反应式编程的概念对我来说是一个非常新的,我仍然处于这种范式转换的过程中。
考虑以下代码:
Mono.just("ONE")
.map(item -> func(" A " + item))
.map(item -> func(" B " + item))
.map(item -> func(" C " + item))
.subscribe(System.out::println);
Mono.just("TWO")
.map(item -> func(" A " + item))
.map(item -> func(" B " + item))
.map(item -> func(" C " + item))
.subscribe(System.out::println);
我从文档中了解到,在订阅"之前,事件处理链没有任何反应。函数被调用。
但在内部,spring使用(如果愿意)对于" map"中的每个函数异步使用单独的线程。功能?如果春天使用"单身"这些链的线程,那么这里的真正目的是什么?它不是基于不同语法的阻塞和单线程模型吗?
我观察到代码总是按顺序运行并且具有相同的线程。什么是spring webflux的线程模型?
答案 0 :(得分:3)
反应式编程是一种编程范式,因此它不会对技术实现做出任何假设。
The reactive manifesto描述了反应系统,并在桌面上引入了异步通信和背压。除此之外,它也没有对技术细节做出任何假设。
Spring Reactor是Webflux的基础,它是一个允许您轻松构建反应系统并遵循反应式编程范例的库。
流使用的线程取决于发布者。默认是使用当前线程。如果发布者是同步的,则在没有任何干预的情况下,流不能是异步的。如果发布者阻止,则流阻塞。但请采用以下示例:
Flux.interval(Duration.ofMillis(100))
.take(2)
.subscribe(i -> System.out.println(Thread.currentThread().getName()));
Flux.interval
在另一个线程上发布,因此链在另一个线程中异步运行。
让我们看另一个例子:
Scheduler scheduler = Schedulers.newElastic("foo");
Flux<Integer> flux = Flux.just(1, 2)
.subscribeOn(scheduler);
flux.subscribe(i -> System.out.println(Thread.currentThread().getName()));
flux.subscribe(i -> System.out.println(Thread.currentThread().getName()));
您会注意到每个订阅者都在自己的线程上运行(尽管来自同一个线程池)。 publishOn
运算符类似。
如果您订阅了发布者,则可以使用相同的编程范例,无论它是同步还是异步。您可以通过添加subscribeOn
或publishOn
运算符来引入异步行为。
答案 1 :(得分:1)
<强> TL; DR:
不,它不是具有不同语法的单线程模型。 Project Reactor尽可能尝试使用主线程来避免上下文切换。此外,它还提供了特殊的运算符,允许您指定先前运行的线程。
例如,此修改示例将在不同的线程上运行; as subscribeOn
运算符定义整个链运行的线程池:
Mono.just("ONE")
.map(item -> func(" A " + item))
.map(item -> func(" B " + item))
.map(item -> func(" C " + item))
.subscribeOn(Schedulers.elastic())
.subscribe(item -> {
System.out.println(Thread.currentThread().getName() + " " + item);
});
Mono.just("TWO")
.map(item -> func(" A " + item))
.map(item -> func(" B " + item))
.map(item -> func(" C " + item))
.subscribeOn(Schedulers.elastic())
.subscribe(item -> {
System.out.println(Thread.currentThread().getName() + " " + item);
});
在这种情况下,两个操作都在elastic-x
线程上执行;没有阻塞主线程。每次运行时,操作的顺序可能会有所不同。