Order
This paper mainly studies the encapsulation of HttpClient of reactor-netty by WebClient of spring 5.
DefaultWebClientBuilder
spring-webflux-5.0.2.RELEASE-sources.jar! /org/springframework/web/reactive/function/client/DefaultWebClientBuilder.java
@Override
public WebClient build() {
ExchangeFunction exchange = initExchangeFunction();
ExchangeFunction filteredExchange = (this.filters != null ? this.filters.stream()
.reduce(ExchangeFilterFunction::andThen)
.map(filter -> filter.apply(exchange))
.orElse(exchange) : exchange);
return new DefaultWebClient(filteredExchange, initUriBuilderFactory(),
unmodifiableCopy(this.defaultHeaders), unmodifiableCopy(this.defaultCookies),
new DefaultWebClientBuilder(this));
}
The build here calls the initExchangeFunction method
private ExchangeFunction initExchangeFunction() {
if (this.exchangeFunction != null) {
return this.exchangeFunction;
}
else if (this.connector != null) {
return ExchangeFunctions.create(this.connector, this.exchangeStrategies);
}
else {
return ExchangeFunctions.create(new ReactorClientHttpConnector(), this.exchangeStrategies);
}
}
New here is a ReactorClientHttpConnector
ReactorClientHttpConnector
spring-web-5.0.2.RELEASE-sources.jar! /org/springframework/http/client/reactive/ReactorClientHttpConnector.java
/**
* Create a Reactor Netty {@link ClientHttpConnector}
* with default {@link ClientOptions} and HTTP compression support enabled.
*/
public ReactorClientHttpConnector() {
this.httpClient = HttpClient.builder()
.options(options -> options.compression(true))
.build();
}
You can see that this constructor uses reactor/ipc/netty/http/client/http client
DefaultWebClient
spring-webflux-5.0.2.RELEASE-sources.jar! /org/springframework/web/reactive/function/client/DefaultWebClient.java
@Override
public RequestHeadersUriSpec<?> get() {
return methodInternal(HttpMethod.GET);
}
@Override
public RequestHeadersUriSpec<?> head() {
return methodInternal(HttpMethod.HEAD);
}
@Override
public RequestBodyUriSpec post() {
return methodInternal(HttpMethod.POST);
}
@Override
public RequestBodyUriSpec put() {
return methodInternal(HttpMethod.PUT);
}
@Override
public RequestBodyUriSpec patch() {
return methodInternal(HttpMethod.PATCH);
}
@Override
public RequestHeadersUriSpec<?> delete() {
return methodInternal(HttpMethod.DELETE);
}
@Override
public RequestHeadersUriSpec<?> options() {
return methodInternal(HttpMethod.OPTIONS);
}
@Override
public RequestBodyUriSpec method(HttpMethod httpMethod) {
return methodInternal(httpMethod);
}
@SuppressWarnings("unchecked")
private RequestBodyUriSpec methodInternal(HttpMethod httpMethod) {
return new DefaultRequestBodyUriSpec(httpMethod);
}
DefaultWebClient mainly returns RequestHeadersUriSpec or RequestBodyUriSpec to GET, HEAD, POST, PUT, PATCH, DELETE, OPTIONS method packages
@Override
public Mono<ClientResponse> exchange() {
ClientRequest request = (this.inserter != null ?
initRequestBuilder().body(this.inserter).build() :
initRequestBuilder().build());
return exchangeFunction.exchange(request).switchIfEmpty(NO_HTTP_CLIENT_RESPONSE_ERROR);
}
Finally, the call to the exchangeFunction is encapsulated in the exchange method, where switchfunction returns reactor.core.publisher.monoswitchifempty < clientresponse >
spring-webflux-5.0.2.RELEASE-sources.jar! /org/springframework/web/reactive/function/client/ExchangeFunctions.java
public Mono<ClientResponse> exchange(ClientRequest request) {
Assert.notNull(request, "'request' must not be null");
return this.connector
.connect(request.method(), request.url(),
clientHttpRequest -> request.writeTo(clientHttpRequest, this.strategies))
.log("org.springframework.web.reactive.function.client", Level.FINE)
.map(clientHttpResponse -> new DefaultClientResponse(clientHttpResponse,
this.strategies));
}
The connect method of ReactorClientHttpConnector is called here
spring-web-5.0.2.RELEASE-sources.jar! /org/springframework/http/client/reactive/ReactorClientHttpConnector.java
public Mono<ClientHttpResponse> connect(HttpMethod method, URI uri,
Function<? super ClientHttpRequest, Mono<Void>> requestCallback) {
if (!uri.isAbsolute()) {
return Mono.error(new IllegalArgumentException("URI is not absolute: " + uri));
}
return this.httpClient
.request(adaptHttpMethod(method),
uri.toString(),
request -> requestCallback.apply(adaptRequest(method, uri, request)))
.map(this::adaptResponse);
}
Request method for HttpClient of reactor-netty last called by connect method.
Summary
The webflux part of spring 5 is mainly based on reactor project, and WebClient is also implemented based on reactor-netty, which mainly encapsulates some UriSpec and other convenient methods.
See spring-webflux-5.0.2.release-sources.jar! /org/springframework/web/reactive/function/client/WebClient.java