zoukankan      html  css  js  c++  java
  • 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的逻辑。由于我们面向对象,所以会有这些抽象与组合的,习惯于这种代码风格还是挺重要的。

  • 相关阅读:
    线程原理
    【小白日记】JavaEE当中 JDBC通过Dao层实现增删改查 CRUD
    【小白日记】Java学习 JDBC通过 junit单元测试编写 CRUD 数据库的增删改查
    【转载】javaEE体系结构
    【小白日记】数据库中的CRUD sql 语句整理
    【小白日记】Java中关于使用JDBC连接Mysql数据库的笔记整理
    【小白日记】Java 多态中的两种类型转换
    待审核测试
    【小白日记】Java中多态的理解随记
    【小白日记】Attribute "scope" must be declared for element type "bean"问题解决方式 以及bean的理解 对Spring的初识和学习(4)
  • 原文地址:https://www.cnblogs.com/lay2017/p/11742217.html
Copyright © 2011-2022 走看看