| This version is still in development and is not considered stable yet. For the latest stable version, please use Spring Framework 6.2.12! | 
Synchronous Use
WebClient can be used in synchronous style by blocking at the end for the result:
- 
Java 
- 
Kotlin 
Person person = client.get().uri("/person/{id}", i).retrieve()
	.bodyToMono(Person.class)
	.block();
List<Person> persons = client.get().uri("/persons").retrieve()
	.bodyToFlux(Person.class)
	.collectList()
	.block();val person = runBlocking {
	client.get().uri("/person/{id}", i).retrieve()
			.awaitBody<Person>()
}
val persons = runBlocking {
	client.get().uri("/persons").retrieve()
			.bodyToFlow<Person>()
			.toList()
}However if multiple calls need to be made, it’s more efficient to avoid blocking on each response individually, and instead wait for the combined result:
- 
Java 
- 
Kotlin 
Mono<Person> personMono = client.get().uri("/person/{id}", personId)
		.retrieve().bodyToMono(Person.class);
Mono<List<Hobby>> hobbiesMono = client.get().uri("/person/{id}/hobbies", personId)
		.retrieve().bodyToFlux(Hobby.class).collectList();
Map<String, Object> data = Mono.zip(personMono, hobbiesMono, (person, hobbies) -> {
			Map<String, String> map = new LinkedHashMap<>();
			map.put("person", person);
			map.put("hobbies", hobbies);
			return map;
		})
		.block();val data = runBlocking {
		val personDeferred = async {
			client.get().uri("/person/{id}", personId)
					.retrieve().awaitBody<Person>()
		}
		val hobbiesDeferred = async {
			client.get().uri("/person/{id}/hobbies", personId)
					.retrieve().bodyToFlow<Hobby>().toList()
		}
		mapOf("person" to personDeferred.await(), "hobbies" to hobbiesDeferred.await())
	}The above is merely one example. There are lots of other patterns and operators for putting together a reactive pipeline that makes many remote calls, potentially some nested, interdependent, without ever blocking until the end.
| With  |