웹 클라이언트가reactor-netty에 대한 봉인

5810 단어

순서


본고는 주로 spring5의 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);
        }
    }

여기 Reactor Client Http Connector가 새로 생겼습니다.

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 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
spring-webflux-5.0.2.RELEASE-sources.jar!/org/springframework/web/reactive/function/client/ExchangeFunctions.java
        public Mono 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 connect(HttpMethod method, URI uri,
            Function super ClientHttpRequest, Mono> 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 방법입니다.

작은 매듭


spring5의 웹flux 부분은 주로reactor 프로젝트를 바탕으로 하고 WebClient도reactor-netty를 바탕으로 실현하며 주로 UriSpec 및 기타 편리한 방법을 봉인했다.
인터페이스는spring-webflux-5.0.2입니다.RELEASE-sources.jar!/org/springframework/web/reactive/function/client/WebClient.java

좋은 웹페이지 즐겨찾기