Spring webclient 是非阻塞客户端吗?
Is Spring webclient non-blocking client?
我不了解响应式网络客户端的工作原理。它说 spring webclient 是非阻塞客户端,但是这个 webclient 似乎在等待来自远程 api 的 onComplete() 信号,然后它可以处理从远程 api 发出的每个项目。
我期望当从目标 api
触发 onNext() 时,webclient 可以处理每个项目
我是 spring webflux 领域的新手。我读到了它,它说它使用 netty 作为默认服务器。这个 netty 使用 eventloop。因此,为了了解它是如何工作的,我尝试创建 2 个小应用程序、客户端和服务器。
仅限服务器应用 return 简单通量,每个项目延迟 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 : ");
}
客户:
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();
}
来自服务器的日志:
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()
来自客户端的日志:
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()
我希望客户端不会等待 4 秒然后得到实际结果。
如您所见,服务器在 22:44:21.126 开始发出 onNext(),客户端在 22:44:24.159 获得结果。
所以我不明白,如果 webclient 有这种行为,为什么它被称为非阻塞客户端。
WebClient在某种意义上是non-blocking,通过WebClient发送HTTP请求的线程不会被IO操作阻塞。
当响应可用时,netty 将通知其中一个工作线程,它会根据您定义的反应流操作来处理响应。
在您的示例中,服务器将等到 Flux 中的所有元素都可用(4 秒),将它们序列化到 JSON 数组,并在单个 HTTP 响应中将其发回。
客户端等待这个单一的响应,但在此期间它的线程没有被阻塞。
如果要实现流式传输效果,需要利用不同的content-type或WebSockets等底层协议。
Check-out 以下关于 application/stream+json
content-type 的 SO 线程:
我不了解响应式网络客户端的工作原理。它说 spring webclient 是非阻塞客户端,但是这个 webclient 似乎在等待来自远程 api 的 onComplete() 信号,然后它可以处理从远程 api 发出的每个项目。 我期望当从目标 api
触发 onNext() 时,webclient 可以处理每个项目我是 spring webflux 领域的新手。我读到了它,它说它使用 netty 作为默认服务器。这个 netty 使用 eventloop。因此,为了了解它是如何工作的,我尝试创建 2 个小应用程序、客户端和服务器。 仅限服务器应用 return 简单通量,每个项目延迟 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 : ");
}
客户:
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();
}
来自服务器的日志:
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()
来自客户端的日志:
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()
我希望客户端不会等待 4 秒然后得到实际结果。 如您所见,服务器在 22:44:21.126 开始发出 onNext(),客户端在 22:44:24.159 获得结果。 所以我不明白,如果 webclient 有这种行为,为什么它被称为非阻塞客户端。
WebClient在某种意义上是non-blocking,通过WebClient发送HTTP请求的线程不会被IO操作阻塞。 当响应可用时,netty 将通知其中一个工作线程,它会根据您定义的反应流操作来处理响应。
在您的示例中,服务器将等到 Flux 中的所有元素都可用(4 秒),将它们序列化到 JSON 数组,并在单个 HTTP 响应中将其发回。
客户端等待这个单一的响应,但在此期间它的线程没有被阻塞。
如果要实现流式传输效果,需要利用不同的content-type或WebSockets等底层协议。
Check-out 以下关于 application/stream+json
content-type 的 SO 线程: