问题
I don't understand reactive webclient works. It says that spring webclient is non-blocking client, but this webclient seems waiting signal onComplete() from remote api, then it can process each item that emitted from the remote api. I'm expecting that webclient can process each item when onNext() is fired from the target api
I'm new in the spring webflux worlds. I read about it and it says it uses netty as default server. And this netty using eventloop. So to understand how it works I try to create 2 small apps, client and server. Server app only return simple flux with delay 1 second each item. Client app using webclient to call remote api.
Server:
@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 : ");
}
Client:
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();
}
Log from server:
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()
Log from client:
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()
I'm expecting that client won't wait for 4 seconds then get the actual result. As you can see that server start emit onNext() on 22:44:21.126, and client get result on 22:44:24.159. So I don't understand why webclient is called non-blocking client if it has this behaviour.
回答1:
The WebClient is non-blocking in a sense that the thread sending HTTP requests through the WebClient is not blocked by the IO operation. When the response is available, netty will notify one of the worker threads and it will process the response according to the reactive stream operations that you defined.
In your example the server will wait until all the elements in a Flux are available (4 seconds), serialize them to the JSON array, and send it back in a single HTTP response.
The client waits for this single response, but non of its threads are blocked during this period.
If you want to achieve the streaming effect, you need to leverage different content-type or the underlying protocol like WebSockets.
Check-out the following SO thread about the application/stream+json
content-type:
Spring WebFlux Flux behavior with non streaming application/json
来源:https://stackoverflow.com/questions/55939068/is-spring-webclient-non-blocking-client