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连接(如果有需要写入数据则写入到输出流),整体还是比较简单的。
restTemplate源码解析(四)执行ClientHttpRequest请求对象的更多相关文章
- restTemplate源码解析(目录)
restTemplate是spring实现的,基于restful风格的http请求模板.使用restTemplate可以简化请求操作的复杂性,同时规范了代码风格.本系列文章,将根据以下目录顺序,从源码 ...
- Mybatis源码解析(四) —— SqlSession是如何实现数据库操作的?
Mybatis源码解析(四) -- SqlSession是如何实现数据库操作的? 如果拿一次数据库请求操作做比喻,那么前面3篇文章就是在做请求准备,真正执行操作的是本篇文章要讲述的内容.正如标题一 ...
- Sentinel源码解析四(流控策略和流控效果)
引言 在分析Sentinel的上一篇文章中,我们知道了它是基于滑动窗口做的流量统计,那么在当我们能够根据流量统计算法拿到流量的实时数据后,下一步要做的事情自然就是基于这些数据做流控.在介绍Sentin ...
- MySQL源码解析之执行计划
MySQL源码解析之执行计划 MySQL执行计划介绍 MySQL执行计划代码概览 MySQL执行计划总结 一.MySQL执行计划介绍 在MySQL中,执行计划的实现是基于JOIN和QEP_TAB这两个 ...
- Dubbo 源码解析四 —— 负载均衡LoadBalance
欢迎来我的 Star Followers 后期后继续更新Dubbo别的文章 Dubbo 源码分析系列之一环境搭建 Dubbo 入门之二 --- 项目结构解析 Dubbo 源码分析系列之三 -- 架构原 ...
- iOS即时通讯之CocoaAsyncSocket源码解析四
原文 前言: 本文为CocoaAsyncSocket源码系列中第二篇:Read篇,将重点涉及该框架是如何利用缓冲区对数据进行读取.以及各种情况下的数据包处理,其中还包括普通的.和基于TLS的不同读取操 ...
- React的React.createContext()源码解析(四)
一.产生context原因 从父组件直接传值到孙子组件,而不必一层一层的通过props进行传值,相比较以前的那种传值更加的方便.简介. 二.context的两种实现方式 1.老版本(React16.x ...
- restTemplate源码解析(五)处理ClientHttpResponse响应对象
所有文章 https://www.cnblogs.com/lay2017/p/11740855.html 正文 上一篇文章中,我们执行了ClientHttpRequest与服务端进行交互.并返回了一个 ...
- 【原创】angularjs1.3.0源码解析之执行流程
Angular执行流程 前言 发现最近angularjs在我厂的应用变得很广泛,下周刚好也有个angular项目要着手开始做,所以先做了下功课,从源代码开始入手会更深刻点,可能讲的没那么细,侧重点在于 ...
随机推荐
- Android:Mstar Android8.0平台音量控制流程
一.Speaker 音量.静音流程分析 java层音量设置首先调用到的是AudioManager.java中的方法,在这里有两种方法可以设置音量 setStreamVolume 和 adjustStr ...
- Android仿微信底部选项卡
第一步 添加依赖 dependencies { compile 'com.yinglan.alphatabs:library:1.0.5' } 第二步 布局使用 <?xml version=&q ...
- 视频软件——ffmpeg
1.官网下载地址:http://ffmpeg.org/download.html ffplay.exe ffplay是用于播放的应用程序. ffplay name.mp4 ffprobe.exe ff ...
- Ubuntu 16.04 haproxy 简单配置应用
HAproxy HAProxy是一个使用C语言编写的自由及开放源代码软件,其提供高可用性.负载均衡,以及基于TCP和HTTP的应用程序代理. 测试环境 ubuntu16.04 192.168.20 ...
- 树莓派连接显示器后设置ssh服务开机自动开启
进入命令行,然后执行: cd /boot sudo touch ssh sudo restart -r now 然后就重新启动了,重启好了会有依据提示. 然后可以输入ssh localhost进行一下 ...
- JS CSS写下拉菜单 竖行
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8&quo ...
- Shiro加盐加密
接本人的上篇文章<Shiro认证.角色.权限>,这篇文章我们来学习shiro的加盐加密实现 自定义Realm: package com.czhappy.realm; import org. ...
- js修改css属性值
推荐用dom.style.setProperty('属性','属性值'); 例如: $("#id")[0].style.setProperty('margin-top','1px' ...
- Chocolate Eating【二分】
题目链接:https://ac.nowcoder.com/acm/contest/1577/K 题目大意: 给出n块巧克力,m天吃完.每块巧克力有a[i]快乐值,每天可以选择吃任意块或者不吃巧克力(按 ...
- 【leetcode算法-简单】66. 加一
[题目描述] 给定一个由整数组成的非空数组所表示的非负整数,在该数的基础上加一. 最高位数字存放在数组的首位, 数组中每个元素只存储单个数字. 你可以假设除了整数 0 之外,这个整数不会以零开头. 示 ...