http调用之RestTemplate
核心方法为org.springframework.web.client.RestTemplate.doExecute(URI, HttpMethod, RequestCallback, ResponseExtractor<T>)
方法内容如下:

其中,重点在下面这三行:

ClientHttpRequest是http请求调用的抽象,具体实现有jdk自带的以及apache的httpclient,实现类如下:

simple开头的是使用jdk自带的net操作,Components的底层是httpclient操作。
AbstractBufferingClientHttpRequest为缓存requestbody的基类,内部bufferedOutput保存了requestbody的内容,避免流的二次读取会导致读取不到数据。
那么,到底是哪里给这个ByteArrayOutputStream对象赋值的呢?答案就在org.springframework.web.client.RestTemplate.HttpEntityRequestCallback,注释讲得很清楚:

在上面讲到的重点强调的三行代码中,调用了org.springframework.web.client.RestTemplate.HttpEntityRequestCallback.doWithRequest(ClientHttpRequest)方法,这个方法里面根据requestContentType等信息,在HttpMessageConverters列表中寻找合适的HttpMessageConverter,利用这些httpMessageConverter天然的write方法将requestBody的内容经过处理转换写入入参HttpOutputMessage对应的getBody方法返回的OutputStream流中。然而,我们这里的ClientHttpRequest接口继承自HttpOutputMessage,AbstractClientHttpRequest的getBody实现调用子类的getBodyInternal方法,重点来了,AbstractBufferingClientHttpRequest的getBodyInternal返回的就是bufferedOutput,也就是缓存的ByteArrayOutputStream。到这里,缓存的requestbody数据有了。再啰嗦一句,使用HttpEntityRequestCallback的都是post请求的,get请求用的AcceptHeaderRequestCallback。
那么,问题来了,什么情况下会用这个缓存数据呢?我们看下AbstractBufferingClientHttpRequest的子类就知道了。
这里,又要回到刚刚的三行重点代码,doExecute的时候调用createRequest方法返回ClientHttpRequest,实际调用父类方法org.springframework.http.client.support.HttpAccessor.createRequest(URI, HttpMethod):
org.springframework.http.client.support.InterceptingHttpAccessor.getRequestFactory()方法如下:

如果设置了拦截器就返回InterceptingClientHttpRequestFactory,并将restTemplete原有的RequestFactory作为参数传入。
该factory创建的是org.springframework.http.client.InterceptingClientHttpRequest,该类重写的executeInternal方法通过内部类InterceptingRequestExecution实现interceptors顺序执行,当迭代结束后,通过之前传进来的requestFactory创建ClientHttpRequest,并将body copy给刚刚创建的request的body,并调用execute方法,方法内容如下:

其实,InterceptingClientHttpRequest本身就带有requestbody缓存copy功能,所以无需在创建restTemplate时包装一个BufferingClientHttpRequestFactory,直接使用HttpComponentsClientHttpRequestFactory即可,这个factory自带bufferRequestBody功能。
相信大部分同学在项目中都是选择apache的httpclient发送http请求,所以,这里我们重点看下org.springframework.http.client.HttpComponentsClientHttpRequestFactory,我们看下createRequest方法:
public ClientHttpRequest createRequest(URI uri, HttpMethod httpMethod) throws IOException {
HttpClient client = getHttpClient();
HttpUriRequest httpRequest = createHttpUriRequest(httpMethod, uri);
postProcessHttpRequest(httpRequest);
HttpContext context = createHttpContext(httpMethod, uri);
if (context == null) {
context = HttpClientContext.create();
}
// Request configuration not set in the context
if (context.getAttribute(HttpClientContext.REQUEST_CONFIG) == null) {
// Use request configuration given by the user, when available
RequestConfig config = null;
if (httpRequest instanceof Configurable) {
config = ((Configurable) httpRequest).getConfig();
}
if (config == null) {
config = createRequestConfig(client);
}
if (config != null) {
context.setAttribute(HttpClientContext.REQUEST_CONFIG, config);
}
}
// 默认情况下bufferRequestBody为true,创建使用缓存的body作为请求体
if (this.bufferRequestBody) {
return new HttpComponentsClientHttpRequest(client, httpRequest, context);
}
else {
return new HttpComponentsStreamingClientHttpRequest(client, httpRequest, context);
}
}
看下上面注释的类的下面方法org.springframework.http.client.HttpComponentsClientHttpRequest.executeInternal(HttpHeaders, byte[]):

这个类也是继承自AbstractBufferingClientHttpRequest,所以刚刚InterceptingRequestExecution迭代结束后getBody返回的就是缓存的bufferedOutput,到这里执行的时候就将bufferedOutput作为ByteArrayEntity发送http请求。至此,结束。
http调用之RestTemplate的更多相关文章
- SpringCloud实现服务间调用(RestTemplate方式)
上一篇文章<SpringCloud搭建注册中心与服务注册>介绍了注册中心的搭建和服务的注册,本文将介绍下服务消费者调用服务提供者的过程. 本文目录 一.服务调用流程二.服务提供者三.服务消 ...
- spring boot / cloud (八) 使用RestTemplate来构建远程调用服务
spring boot / cloud (八) 使用RestTemplate来构建远程调用服务 前言 上周因家里突发急事,请假一周,故博客没有正常更新 RestTemplate介绍: RestTemp ...
- SpringBoot系列(一)RestTemplate
作为springBoot的开篇系列,RestTemplate只能表示我只是个意外 what RestTemplate是spring提供的用于访问rest服务的客户端(其实类似Apache的HttpCl ...
- Spring Boot使用RestTemplate消费REST服务的几个问题记录
我们可以通过Spring Boot快速开发REST接口,同时也可能需要在实现接口的过程中,通过Spring Boot调用内外部REST接口完成业务逻辑. 在Spring Boot中,调用REST Ap ...
- 如何使用RestTemplate访问restful服务
一. 什么是RestTemplate 传统情况下在java代码里访问restful服务,一般使用Apache的HttpClient.不过此种方法使用起来太过繁琐.spring提供了一种简单便捷的模板类 ...
- springcloud-feign组件实现声明式的调用
11.使用feign实现声明式的调用 使用RestTemplate+ribbon已经可以完成对服务端负载均衡的调用,为什么还要使用feign? @RequestMapping("/hi&qu ...
- Spring Cloud(三):声明式调用
声明式服务调用 前面在使用spring cloud时,通常都会利用它对RestTemplate的请求拦截来实现对依赖服务的接口调用,RestTemplate实现了对http的请求封装处理,形成了一套模 ...
- SpringCloud系列-利用Feign实现声明式服务调用
上一篇文章<手把手带你利用Ribbon实现客户端的负载均衡>介绍了消费者通过Ribbon调用服务实现负载均衡的过程,里面所需要的参数需要在请求的URL中进行拼接,但是参数太多会导致拼接字符 ...
- RestTemplate相关组件:ClientHttpRequestInterceptor【享学Spring MVC】
每篇一句 做事的人和做梦的人最大的区别就是行动力 前言 本文为深入了解Spring提供的Rest调用客户端RestTemplate开山,对它相关的一些组件做讲解. Tips:请注意区分RestTemp ...
随机推荐
- opencv:USM锐化
USM:unsharp mask 对小的细节干扰小,对大的细节进行锐化 Mat dst; Mat blur_image; GaussianBlur(src, blur_image, Size(3, 3 ...
- sqli-libs(32-37(宽字节注入)关)
补充知识:宽字节注入 定义:GB2312.GBK.GB18030.BIG5.Shift_JIS等这些都是常说的宽字节,实际上只有两字节.宽字节带来的安全问题主要是吃ASCII字符(一字节)的现象,即将 ...
- Unity UGUI事件接口概述
UGUI 系统虽然提供了很多封装好的组件,但是要实现一些特定的功能还是显得非常有限,这时候就需要使用事件接口来完成UI功能的实现.比如我们想实现鼠标移动到图片上时自动显示图片的文字介绍,一般思路会想到 ...
- 6_7 树的层次遍历(UVa122)<二叉树的动态创建与BFS>
树状结构在计算机科学的许多领域中都相当重要.本问题牵涉到建立树及走访树.给你一二叉树,你的任务是写一个程序来打印依「阶层(level-order)」走访的结果.在本问题中,二叉树的每个节点含有一个正整 ...
- socket模块(套接字模块)
socket模块(套接字模块) 一.最简单版本(互传一次就结束) # 客户端 import socket client = socket.socket() client.connect(('127.0 ...
- 吴裕雄 python 人工智能——基于Mask_RCNN目标检测(3)
import os import sys import random import math import re import time import numpy as np import cv2 i ...
- STM32 MDK C 常见易错点
1.MDK编译器单字节的负数-1,-2,-3... ... 处理:存储,类型转换,位对齐. char 定义的变量在运算过程尤其类型转换,逻辑比大少会被当做 unsigned char 处理,这里很容易 ...
- Abaqus脚本接口及简单应用
目录 1.脚本接口简介 2. 宏录制 3. 宏回放 4. 宏编辑 5. 宏控制 1.脚本接口简介 Abaqus中的脚本接口(ASI)是在Python应用程序的基础上开发的,基于Abaqus中的脚本接口 ...
- BZOJ - 2038 小Z的袜子(普通莫队)
题目链接:小Z的袜子 题意:$n$只袜子,$m$个询问,每次回答有多大概率在$[L,R]$区间内抽到两只颜色相同的袜子 思路:普通莫队,如果两个询问左端点在一个块内,则按询问右端点排序,否则按照所在块 ...
- Shiro入门学习之散列算法与凭证配置(六)
一.散列算法概述 散列算法一般用于生成数据的摘要信息,是一种不可逆的算法,一般适合存储密码之类的数据,常见的散列算法如MD5.SHA等,一般进行散列时最好提供一个salt(“盐”),什么意思?举个栗子 ...