webclient对reactor-netty的封装

本文主要研究一下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主要对GET、HEAD、POST、PUT、PATCH、DELETE、OPTIONS方法封装返回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>

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));
        }
这里调用了ReactorClientHttpConnector的connect方法

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);
    }
connect方法最后调用的reactor-netty的HttpClient的request方法。

小结

spring 5的webflux部分主要基于reactor项目来的,WebClient也是基于reactor-netty来实现,主要是封装了一些UriSpec及其他便利方法。

接口见spring-webflux-5.0.2.RELEASE-sources.jar!/org/springframework/web/reactive/function/client/WebClient.java

相关文章

react 中的高阶组件主要是对于 hooks 之前的类组件来说的,如...
我们上一节了解了组件的更新机制,但是只是停留在表层上,例...
我们上一节了解了 react 的虚拟 dom 的格式,如何把虚拟 dom...
react 本身提供了克隆组件的方法,但是平时开发中可能很少使...
mobx 是一个简单可扩展的状态管理库,中文官网链接。小编在接...
我们在平常的开发中不可避免的会有很多列表渲染逻辑,在 pc ...