序
本文主要研究一下 spring 5 的 webClient 对 reactor-netty 的 HttpClient 的封装
- 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));
- }
这里的 build 调用了 initExchangeFunction 方法
- 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 了一个 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();
- }
可以看到这个构造器使用了 reactor/ipc/netty/http/client/HttpClient
- 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 主要对 GETHEADPOSTPUTPATCHDELETEOPTIONS 方法封装返回 RequestHeadersUriSpec 或者 RequestBodyUriSpec
- @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);
- }
最后在 exchange 方法里头封装了对 exchangeFunction 的调用, 这里的 switchIfEmpty 返回的是 reactor.core.publisher.MonoSwitchIfEmpty<ClientResponse>
而 exchangeFunction 底层又是调用 reactor-netty 的 HttpClient
小结
spring 5 的 webflux 部分主要基于 reactor 项目来的, WebClient 也是基于 reactor-netty 来实现, 主要是封装了一些 UriSpec 及其他便利方法
接口见 spring-webflux-5.0.2.RELEASE-sources.jar!/org/springframework/web/reactive/function/client/WebClient.java
来源: https://segmentfault.com/a/1190000013298820