restTemplate源码解析(三)创建ClientHttpRequest请求对象

所有文章

https://www.cnblogs.com/lay2017/p/11740855.html

 

正文

上一篇文章中,我们大体看了一下restTemplate的核心逻辑。再回顾一下核心代码

protected <T> T doExecute(URI url, @Nullable HttpMethod method, @Nullable RequestCallback requestCallback,
        @Nullable ResponseExtractor<T> responseExtractor) throws RestClientException {

    ClientHttpResponse response = null;
    try {
        // 生成请求
        ClientHttpRequest request = createRequest(url, method);
        if (requestCallback != null) {
            // 设置header
            requestCallback.doWithRequest(request);
        }
        // 执行请求,获取响应
        response = request.execute();
        // 处理响应
        handleResponse(url, method, response);
        // 获取响应体对象
        return (responseExtractor != null ? responseExtractor.extractData(response) : null);
    }
    catch (IOException ex) {
        // ... 抛出异常
    }
    finally {
        if (response != null) {
            // 关闭响应流
            response.close();
        }
    }
}

本文将打开createRequest这个创建请求的方法,看看创建请求的实现细节

 

跟进createRequest方法

protected ClientHttpRequest createRequest(URI url, HttpMethod method) throws IOException {
    ClientHttpRequest request = getRequestFactory().createRequest(url, method);
    if (logger.isDebugEnabled()) {
        logger.debug("HTTP " + method.name() + " " + url);
    }
    return request;
}

这里是一个工厂模式,先获取一个ClientHttpRequestFactory的工厂实例,然后将创建的工作委托给工厂处理并返回结果。

 

打开getRequestFactory看看获取的工厂实例(注意:这里不考虑拦截器的部分,所以不向下阅读)

public ClientHttpRequestFactory getRequestFactory() {
    return this.requestFactory;
}

看看requestFactory成员变量

private ClientHttpRequestFactory requestFactory = new SimpleClientHttpRequestFactory();

默认是SimpleClientHttpRequestFactory的实现,当然我们可以自定义实现它。简单起见,本文直接看默认的实现。

 

获取了ClientHttpRequestFactory的实例,我们跟进SimpleClientHttpRequestFactory看看它是怎么实现createRequest方法的

@Override
public ClientHttpRequest createRequest(URI uri, HttpMethod httpMethod) throws IOException {
    // 通过URI生成了connection
    HttpURLConnection connection = openConnection(uri.toURL(), this.proxy);
    // 对Connection进行一些设置
    prepareConnection(connection, httpMethod.name());
    // 返回一个ClientHttpRequest的实现
    if (this.bufferRequestBody) {
        return new SimpleBufferingClientHttpRequest(connection, this.outputStreaming);
    }
    else {
        return new SimpleStreamingClientHttpRequest(connection, this.chunkSize, this.outputStreaming);
    }
}

到这里,我们可以知道SimpleClientHttpRequestFactory其实就是包装了一下HttpUrlConnection。createRequest做了两件事:

1)创建并设置一个HttpUrlConnection

2)构造并返回一个ClientHttpRequest的实例对象

 

打开openConnection方法看看HttpUrlConnection的创建

protected HttpURLConnection openConnection(URL url, @Nullable Proxy proxy) throws IOException {
    URLConnection urlConnection = (proxy != null ? url.openConnection(proxy) : url.openConnection());
    if (!HttpURLConnection.class.isInstance(urlConnection)) {
        throw new IllegalStateException("HttpURLConnection required for [" + url + "] but got: " + urlConnection);
    }
    return (HttpURLConnection) urlConnection;
}

很简单地通过URL对象的openConnection方法返回了一个UrlConnection。

 

再打开prepareConnection看看设置了啥

protected void prepareConnection(HttpURLConnection connection, String httpMethod) throws IOException {
    if (this.connectTimeout >= 0) {
        connection.setConnectTimeout(this.connectTimeout);
    }
    if (this.readTimeout >= 0) {
        connection.setReadTimeout(this.readTimeout);
    }

    connection.setDoInput(true);

    if ("GET".equals(httpMethod)) {
        connection.setInstanceFollowRedirects(true);
    }
    else {
        connection.setInstanceFollowRedirects(false);
    }

    if ("POST".equals(httpMethod) || "PUT".equals(httpMethod) ||
            "PATCH".equals(httpMethod) || "DELETE".equals(httpMethod)) {
        connection.setDoOutput(true);
    }
    else {
        connection.setDoOutput(false);
    }

    connection.setRequestMethod(httpMethod);
}

也是一些HttpUrlConnection很常见的设置,超时时间,允许输入输出,请求方法啥的

 

再回到刚刚的createRequest方法

private boolean bufferRequestBody = true;

@Override
public ClientHttpRequest createRequest(URI uri, HttpMethod httpMethod) throws IOException {
    // 通过URI生成了connection
    HttpURLConnection connection = openConnection(uri.toURL(), this.proxy);
    // 对Connection进行一些设置
    prepareConnection(connection, httpMethod.name());
    // 返回一个ClientHttpRequest的实现
    if (this.bufferRequestBody) {
        return new SimpleBufferingClientHttpRequest(connection, this.outputStreaming);
    }
    else {
        return new SimpleStreamingClientHttpRequest(connection, this.chunkSize, this.outputStreaming);
    }
}

bufferRequestBody默认是true,将会返回ClientHttpRequest的默认实现SimpleBufferingClientHttpRequest的实例对象。

 

我们保持好奇心,瞄一眼SimpleBufferingClientHttpRequest的类图关系吧。

 

总结

createRequest方法通过ClientHttpRequestFactory创建并返回了一个ClientHttpRequest的实例。整体逻辑还是挺简单的,如果放到面向过程的代码里或许就是各种ifelse的逻辑。由于我们面向对象,所以会有这些抽象与组合的,习惯于这种代码风格还是挺重要的。

 

posted @ 2019-10-26 11:09  __lay  阅读(3419)  评论(0编辑  收藏  举报