Spring webclient 是非阻塞客户端吗?

Ant*_* Tb 4 reactor-netty spring-webflux spring-webclient

我不明白反应式 webclient 的工作原理。它说spring webclient是非阻塞客户端,但是这个webclient似乎在等待来自远程api的onComplete()信号,然后它可以处理从远程api发出的每个项目。我期望当 onNext() 从目标 api 被触发时,webclient 可以处理每个项目

我是春季 webflux 世界的新手。我读到它,它说它使用 netty 作为默认服务器。而这个 netty 使用 eventloop。所以为了理解它是如何工作的,我尝试创建 2 个小应用程序,客户端和服务器。服务器应用程序只返回简单的通量,每个项目延迟 1 秒。客户端应用程序使用 webclient 调用远程 api。

服务器:

@GetMapping(ITEM_END_POINT_V1)
public Flux<Item> getAllItems(){
        return Flux.just(new Item(null, "Samsung TV", 399.99),
                new Item(null, "LG TV", 329.99),
                new Item(null, "Apple Watch", 349.99),
                new Item("ABC", "Beats HeadPhones", 
      149.99)).delayElements(Duration.ofSeconds(1)).log("Item : ");
}
Run Code Online (Sandbox Code Playgroud)

客户:

WebClient webClient = WebClient.create("http://localhost:8080");

@GetMapping("/client/retrieve")
public Flux<Item> getAllItemsUsingRetrieve() {
        return webClient.get().uri("/v1/items")
                .retrieve()
                .bodyToFlux(Item.class).log();
}
Run Code Online (Sandbox Code Playgroud)

从服务器登录:

2019-05-01 22:44:20.121  INFO 19644 --- [ctor-http-nio-2] Item :                                   : onSubscribe(FluxConcatMap.ConcatMapImmediate)
2019-05-01 22:44:20.122  INFO 19644 --- [ctor-http-nio-2] Item :                                   : request(unbounded)
2019-05-01 22:44:21.126  INFO 19644 --- [     parallel-1] Item :                                   : onNext(Item(id=null, description=Samsung TV, price=399.99))
2019-05-01 22:44:22.129  INFO 19644 --- [     parallel-2] Item :                                   : onNext(Item(id=null, description=LG TV, price=329.99))
2019-05-01 22:44:23.130  INFO 19644 --- [     parallel-3] Item :                                   : onNext(Item(id=null, description=Apple Watch, price=349.99))
2019-05-01 22:44:24.131  INFO 19644 --- [     parallel-4] Item :                                   : onNext(Item(id=ABC, description=Beats HeadPhones, price=149.99))
2019-05-01 22:44:24.132  INFO 19644 --- [     parallel-4] Item :                                   : onComplete()
Run Code Online (Sandbox Code Playgroud)

从客户端登录:

2019-05-01 22:44:19.934  INFO 24164 --- [ctor-http-nio-2] reactor.Flux.MonoFlatMapMany.1           : onSubscribe(MonoFlatMapMany.FlatMapManyMain)
2019-05-01 22:44:19.936  INFO 24164 --- [ctor-http-nio-2] reactor.Flux.MonoFlatMapMany.1           : request(unbounded)
2019-05-01 22:44:19.940 TRACE 24164 --- [ctor-http-nio-2] o.s.w.r.f.client.ExchangeFunctions       : [7e73de5c] HTTP GET http://localhost:8080/v1/items, headers={}
2019-05-01 22:44:24.159 TRACE 24164 --- [ctor-http-nio-6] o.s.w.r.f.client.ExchangeFunctions       : [7e73de5c] Response 200 OK, headers={masked}
2019-05-01 22:44:24.204  INFO 24164 --- [ctor-http-nio-6] reactor.Flux.MonoFlatMapMany.1           : onNext(Item(id=null, description=Samsung TV, price=399.99))
2019-05-01 22:44:24.204  INFO 24164 --- [ctor-http-nio-6] reactor.Flux.MonoFlatMapMany.1           : onNext(Item(id=null, description=LG TV, price=329.99))
2019-05-01 22:44:24.204  INFO 24164 --- [ctor-http-nio-6] reactor.Flux.MonoFlatMapMany.1           : onNext(Item(id=null, description=Apple Watch, price=349.99))
2019-05-01 22:44:24.204  INFO 24164 --- [ctor-http-nio-6] reactor.Flux.MonoFlatMapMany.1           : onNext(Item(id=ABC, description=Beats HeadPhones, price=149.99))
2019-05-01 22:44:24.205  INFO 24164 --- [ctor-http-nio-6] reactor.Flux.MonoFlatMapMany.1           : onComplete()
Run Code Online (Sandbox Code Playgroud)

我期待客户不会等待 4 秒然后得到实际结果。正如你所看到的,服务器在22:44:21.126开始发出 onNext() ,客户端在22:44:24.159得到结果。所以我不明白为什么 webclient 被称为非阻塞客户端,如果它有这种行为。

Ily*_*ich 5

从某种意义上说,WebClient 是非阻塞的,即通过 WebClient 发送 HTTP 请求的线程不会被 IO 操作阻塞。当响应可用时,netty 将通知其中一个工作线程,它将根据您定义的反应流操作处理响应。

在您的示例中,服务器将等待 Flux 中的所有元素都可用(4 秒),将它们序列化为 JSON 数组,并在单个 HTTP 响应中将其发送回。

客户端等待这个单一的响应,但在此期间没有任何线程被阻塞。

如果要实现流式传输效果,则需要利用不同的内容类型或像 WebSockets 这样的底层协议。查看以下有关application/stream+json内容类型的SO 线程: Spring WebFlux Flux 行为与非流应用程序/json