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与服务端进行交互.并返回了一个 ...
随机推荐
- window 下 某个端口被占用
window 下 某个端口被占用 1. 开始—->运行—->cmd,或者是window+R组合键,调出命令窗口: 2.输入命令:netstat -ano,列出所有端口的情况.在列表中我们观 ...
- Elasticsearch 7.x文档基本操作(CRUD)
官方文档:https://www.elastic.co/guide/en/elasticsearch/reference/current/docs.html 1.添加文档 1.1.指定文档ID PUT ...
- LeetCode_191. Number of 1 Bits
191. Number of 1 Bits Easy Write a function that takes an unsigned integer and return the number of ...
- LeetCode_136. Single Number
136. Single Number Easy Given a non-empty array of integers, every element appears twice except for ...
- cq三期备注说明
1.关于导航栏添加登陆拦截操作
- 添加tomcat8为服务
跟上一篇添加zookeeper为服务基本类似 脚本如下: #!/bin/bash CATALANA_HOME=/usr/local/tomcat8 export JAVA_HOME=/usr/loca ...
- 最新 开创java校招面经 (含整理过的面试题大全)
从6月到10月,经过4个月努力和坚持,自己有幸拿到了网易雷火.京东.去哪儿.开创等10家互联网公司的校招Offer,因为某些自身原因最终选择了开创.6.7月主要是做系统复习.项目复盘.LeetCode ...
- IntelliJ IDEA 简单设置
1.在idea中添加try/catch的快捷键 ctrl+alt+t 2.主题修改 选择菜单栏“File--settings--apperance--theme”,主题选择Darcula: 3.代码字 ...
- 中国大数据企业排行榜V6.0- 5 年后再去看看中几个大数据公司的发展状况
2019年5月27日,首席数据官联盟在贵阳举办的2019中国国际大数据产业博览会上正式发布了<中国大数据企业排行榜V6.0> 本次排行榜新增8个垂直行业和领域.上榜企业是从全国五千多家 ...
- Max coverage disjoint intervals
Assume you have k<=10^5 intervals [a_i, b_i] \in [1,10^18] (some of them may overlap), and you ne ...