restTemplate源码解析(四)执行ClientHttpRequest请求对象

所有文章

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

正文

上一篇文章中,我们创建了一个ClientHttpRequest的实例。本文将继续阅读ClientHttpRequest的执行逻辑。

再次回顾一下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();
        }
    }
}

ClientHttpRequest的默认实现类是SimpleBufferingClientHttpRequest,我们先看看它的继承关系

可以看到,ClientHttpRequest直接被AbstractClientHttpRequest继承,所以我们先从AbstractClientHttpRequest实现的execute方法开始

跟进execute方法

@Override
public final ClientHttpResponse execute() throws IOException {
    assertNotExecuted();
    ClientHttpResponse result = executeInternal(this.headers);
    this.executed = true;
    return result;
}

execute方法前置校验executed这个flag,executeInternal执行完后打了个true的标记。所以一个ClientHttpRequest将只能被执行一次。

继续跟进executeInternal方法,executeInternal方法由AbstractBufferingClientHttpRequest实现

@Override
protected ClientHttpResponse executeInternal(HttpHeaders headers) throws IOException {
    byte[] bytes = this.bufferedOutput.toByteArray();
    if (headers.getContentLength() < 0) {
        headers.setContentLength(bytes.length);
    }
    ClientHttpResponse result = executeInternal(headers, bytes);
    this.bufferedOutput = new ByteArrayOutputStream(0);
    return result;
}

核心逻辑在executeInternal(headers, bytes)里,继续跟进它

executeInternal(headers, bytes)由SimpleBufferingClientHttpRequest实现

@Override
protected ClientHttpResponse executeInternal(HttpHeaders headers, byte[] bufferedOutput) throws IOException {
    addHeaders(this.connection, headers);
    // JDK <1.8 doesn‘t support getOutputStream with HTTP DELETE
    if (getMethod() == HttpMethod.DELETE && bufferedOutput.length == 0) {
        this.connection.setDoOutput(false);
    }
    if (this.connection.getDoOutput() && this.outputStreaming) {
        this.connection.setFixedLengthStreamingMode(bufferedOutput.length);
    }
    this.connection.connect();
    if (this.connection.getDoOutput()) {
        // 写到输出流上
        FileCopyUtils.copy(bufferedOutput, this.connection.getOutputStream());
    }
    else {
        // Immediately trigger the request in a no-output scenario as well
        this.connection.getResponseCode();
    }
    // 响应一个ClientHttpResponse对象
    return new SimpleClientHttpResponse(this.connection);
}

如果开启了输出流,那么FileCopyUtils.copy方法将会把缓冲数据写入到输出流里面。

注意:FileCopyUtils.copy方法在写入完毕后会关闭输出流,所以不需要外部显式关闭。我们看copy方法

public static void copy(byte[] in, OutputStream out) throws IOException {
    Assert.notNull(in, "No input byte array specified");
    Assert.notNull(out, "No OutputStream specified");

    try {
        out.write(in);
    }
    finally {
        try {
            out.close();
        }
        catch (IOException ex) {
        }
    }
}

executerInternal(headers, bytes)方法最后会响应一个SimpleClientHttpResponse实例对象,单纯地包装了Connection对象。

SimpleClientHttpResponse(HttpURLConnection connection) {
    this.connection = connection;
}

显然,后续的处理就是从ClientHttpResponse中读取输入流,然后格式化成一个响应体,最后回收资源。下一篇内容讲述这个

总结

执行ClientHttpRequest逻辑其实就是与服务端创建Connection连接(如果有需要写入数据则写入到输出流),整体还是比较简单的。

原文地址:https://www.cnblogs.com/lay2017/p/11742936.html

时间: 2024-11-04 08:38:56

restTemplate源码解析(四)执行ClientHttpRequest请求对象的相关文章

Mybatis源码解析(四) —— SqlSession是如何实现数据库操作的?

Mybatis源码解析(四) -- SqlSession是如何实现数据库操作的? ??如果拿一次数据库请求操作做比喻,那么前面3篇文章就是在做请求准备,真正执行操作的是本篇文章要讲述的内容.正如标题一样,本篇文章最最核心的要点就是 SqlSession实现数据库操作的源码解析.但按照惯例,我这边依然列出如下的问题: 1. SqlSession 是如何被创建的? 每次的数据库操作都会创建一个新的SqlSession么?(也许有很多同学会说SqlSession是通过 SqlSessionFactor

Spring 源码解析之ViewResolver源码解析(四)

Spring 源码解析之ViewResolver源码解析(四) 1 ViewResolver类功能解析 1.1 ViewResolver Interface to be implemented by objects that can resolve views by name. View state doesn't change during the running of the application, so implementations are free to cache views. I

Android网络编程(七)源码解析OkHttp前篇[请求网络]

相关文章 Android网络编程(一)HTTP协议原理 Android网络编程(二)HttpClient与HttpURLConnection Android网络编程(三)Volley用法全解析 Android网络编程(四)从源码解析volley Android网络编程(五)OkHttp2.x用法全解析 Android网络编程(六)OkHttp3用法全解析 前言 学会了OkHttp3的用法后,我们当然有必要来了解下OkHttp3的源码,当然现在网上的文章很多,我仍旧希望我这一系列文章篇是最简洁易懂

iOS即时通讯之CocoaAsyncSocket源码解析四

原文 前言: 本文为CocoaAsyncSocket源码系列中第二篇:Read篇,将重点涉及该框架是如何利用缓冲区对数据进行读取.以及各种情况下的数据包处理,其中还包括普通的.和基于TLS的不同读取操作等等.注:由于该框架源码篇幅过大,且有大部分相对抽象的数据操作逻辑,尽管楼主竭力想要简单的去陈述相关内容,但是阅读起来仍会有一定的难度.如果不是诚心想学习IM相关知识,在这里就可以离场了... 注:文中涉及代码比较多,建议大家结合源码一起阅读比较容易能加深理解.这里有楼主标注好注释的源码,有需要的

restTemplate源码解析(五)处理ClientHttpResponse响应对象

所有文章 https://www.cnblogs.com/lay2017/p/11740855.html 正文 上一篇文章中,我们执行了ClientHttpRequest与服务端进行交互.并返回了一个ClientHttpResponse的实例对象. 本文将继续最后一个部分,处理请求后的响应. 同样的,我们再次回顾一下restTemplate核心逻辑代码 protected <T> T doExecute(URI url, @Nullable HttpMethod method, @Nullab

AFNetworking2.0源码解析&lt;四&gt;

结构 AFURLResponseSerialization负责解析网络返回数据,检查数据是否合法,把NSData数据转成相应的对象,内置的转换器有json,xml,plist,image,用户可以很方便地继承基类AFHTTPResponseSerializer去解析更多的数据格式,AFNetworking这一套响应解析机制结构很简单,主要就是两个方法: 1.-validateResponse:data:error: 基类AFHTTPResponseSerializer的这个方法检测返回的HTTP

vuex 源码解析(四) mutation 详解

mutation是更改Vuex的store中的状态的唯一方法,mutation类似于事件注册,每个mutation都可以带两个参数,如下: state ;当前命名空间对应的state payload   ;传入的参数,一般是一个对象 创建Vuex.Store()仓库实例时可以通过mutations创建每个mutation 我们不能直接调用一个mutation,而是通过 store.commit来调用,commit可以带两个参数,如下: type ;对应的mutation名 payload ;传入

jquery源码解析:jQuery静态属性对象support详解

jQuery.support是用功能检测的方法来检测浏览器是否支持某些功能.针对jQuery内部使用. 我们先来看一些源码: jQuery.support = (function( support ) { ...... return support;})( {} ); jQuery.support其实就是一个json对象.在火狐浏览器下,打印出support对象: 接下来,我们来看它的源码 jQuery.support = (function( support ) { var input = d

Tomcat关闭过程(Tomcat源码解析四)

我们在Tomcat启动过程(Tomcat源代码阅读系列之三)一文中已经知道Tomcat启动以后,会启动6条线程,他们分别如下: "ajp-bio-8009-AsyncTimeout" daemon prio=5 tid=7f8738afe000 nid=0x115ad6000 waiting on condition [115ad5000] "ajp-bio-8009-Acceptor-0" daemon prio=5 tid=7f8738b05800 nid=0x