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的逻辑。由于我们面向对象,所以会有这些抽象与组合的,习惯于这种代码风格还是挺重要的。
restTemplate源码解析(三)创建ClientHttpRequest请求对象的更多相关文章
- restTemplate源码解析(目录)
restTemplate是spring实现的,基于restful风格的http请求模板.使用restTemplate可以简化请求操作的复杂性,同时规范了代码风格.本系列文章,将根据以下目录顺序,从源码 ...
- Celery 源码解析三: Task 对象的实现
Task 的实现在 Celery 中你会发现有两处,一处位于 celery/app/task.py,这是第一个:第二个位于 celery/task/base.py 中,这是第二个.他们之间是有关系的, ...
- Mybatis源码解析(三) —— Mapper代理类的生成
Mybatis源码解析(三) -- Mapper代理类的生成 在本系列第一篇文章已经讲述过在Mybatis-Spring项目中,是通过 MapperFactoryBean 的 getObject( ...
- ReactiveCocoa源码解析(三) Signal代码的基本实现
上篇博客我们详细的聊了ReactiveSwift源码中的Bag容器,详情请参见<ReactiveSwift源码解析之Bag容器>.本篇博客我们就来聊一下信号量,也就是Signal的的几种状 ...
- ReactiveSwift源码解析(三) Signal代码的基本实现
上篇博客我们详细的聊了ReactiveSwift源码中的Bag容器,详情请参见<ReactiveSwift源码解析之Bag容器>.本篇博客我们就来聊一下信号量,也就是Signal的的几种状 ...
- React的React.createRef()/forwardRef()源码解析(三)
1.refs三种使用用法 1.字符串 1.1 dom节点上使用 获取真实的dom节点 //使用步骤: 1. <input ref="stringRef" /> 2. t ...
- dubbo源码解析-zookeeper创建节点
前言 在之前dubbo源码解析-本地暴露中的前言部分提到了两道高频的面试题,其中一道dubbo中zookeeper做注册中心,如果注册中心集群都挂掉,那发布者和订阅者还能通信吗?在上周的dubbo源码 ...
- vuex 源码解析(三) getter属性详解
有时候我们需要从store中的state中派生出一些状态,例如: <div id="app"> <p>{{reverseMessage}}</p> ...
- restTemplate源码解析(二)restTemplate的核心逻辑
所有文章 https://www.cnblogs.com/lay2017/p/11740855.html 正文 上一篇文章中,我们构造了一个RestTemplate的Bean实例对象.本文将主要了解一 ...
- restTemplate源码解析(五)处理ClientHttpResponse响应对象
所有文章 https://www.cnblogs.com/lay2017/p/11740855.html 正文 上一篇文章中,我们执行了ClientHttpRequest与服务端进行交互.并返回了一个 ...
随机推荐
- Assertion failure in -[UISectionRowData refreshWithSection:tableView:tableViewRowData:]
最近在项目中遇到了 Assertion failure in -[UISectionRowData refreshWithSection:tableView:tableViewRowData:] 这个 ...
- Qt编写自定义控件45-柱状标尺控件
一.前言 这个控件写了很久了,是最早期的一批控件中的一个,和温度计控件类似,都是垂直的进度条,可以设置不同的背景颜色,左侧的刻度也可以自由设定,还提供了动画效果,其实就是开启定时器慢慢的进度到设定的目 ...
- Python使用设计模式中的责任链模式与迭代器模式的示例
Python使用设计模式中的责任链模式与迭代器模式的示例 这篇文章主要介绍了Python使用设计模式中的责任链模式与迭代器模式的示例,责任链模式与迭代器模式都可以被看作为行为型的设计模式,需要的朋友可 ...
- 微信小程序--TabBar不出现
今天打算开始实战一个微信小程序项目,一开始就踩坑了,正确设置了TabBar,但是TabBar就是不能显示出来,后面才找到原因,这里记录下: app.json正确代码: { "pages&qu ...
- nginx+mysql双主搭建
说明:mysql双主架构经过测试在生产环境中使用没有问题,但是还是建议使用读写分离, Mysql主主同步环境部署: centos 7.4 三台云主机:mysql1 :10.1.1.142 mysql2 ...
- LODOP设置同一个任务发送到不同打印机
前面的博文Lodop打印语句最基本结构介绍(什么是一个任务),一个任务只能有一个打印语句(最后PRINT,PRINTA,PREVIEW等),如果执行多个,LODOP会弹出多次,C-LODOP会提示窗口 ...
- SQL 语句是如何执行的
SQL 语句是如何执行的,虽然SQL是声明式语言,我们可以像使用英语一样使用它,不过在RDBMS(关系型数据库管理系统)中,SQL的实现方式还是有差别的.极客教程从数据库的角度来思考一下SQL是如何被 ...
- 【VS开发】Wix 安装教程
original link : http://www.cnblogs.com/stoneniqiu/p/3355086.html 因为项目需要,最近在研究Wix打包部署,园子里也有一些关于wix ...
- 使用Apache服务部署网站(基于IP,域名,端口)
本篇主要学习Apache网站服务程序的基本部署,基于IP地址.主机名(域名).端口号的虚拟主机功能. 1.基于IP地址 首先我们需要在虚拟机中线安装Apache服务程序,Apache服务程序的软件包名 ...
- 哈夫曼编解码压缩解压文件—C++实现
前言 哈夫曼编码是一种贪心算法和二叉树结合的字符编码方式,具有广泛的应用背景,最直观的是文件压缩.本文主要讲述如何用哈夫曼编解码实现文件的压缩和解压,并给出代码实现. 哈夫曼编码的概念 哈夫曼树又称作 ...