之前有一篇文章是分析的Feign, 这边文章来分析Spring中的RestTemplate,下面还会有一篇来分析最新的WebClient,当然这时后话,下面来具体看一下RestTemplate的执行流程。
Get请求流程分析(getForObject)
首先从get方法开始,传入url,返回类型,参数即可,方法原型:
public <T> T getForObject(String url, Class<T> responseType, Map<String, ?> uriVariables) throws RestClientException {
RequestCallback requestCallback = acceptHeaderRequestCallback(responseType);
HttpMessageConverterExtractor<T> responseExtractor =
new HttpMessageConverterExtractor<>(responseType, getMessageConverters(), logger);
return execute(url, HttpMethod.GET, requestCallback, responseExtractor, uriVariables);
}
看到他先创建了一个RequestCallback
类型变量,那么这个是什么呢?
RequestCallback是一个功能接口(FunctionalInterface),里面只有一个方法声明:
void doWithRequest(ClientHttpRequest request) throws IOException;
它是用来操作request的,在请求发送前,为请求添加header,将请求体写入request。
它有两个实现类,一个是AcceptHeaderRequestCallback
实现RequestCalback
,为请求添加请求头;另一个是HttpEntityRequestCallback
,继承自AcceptHeaderRequestCallback
,为请求添加请求头,写入请求体。对于GET
请求它使用的是AcceptHeaderRequestCallback
,即只需要处理请求头,因为GET
请求并没有请求体。
新建完RequestCallback
后又新建了HttpMessageConverterExtractor<T>
类型变量,这个主要是从Response中获取并转换返回对象用的,后面会说到。
然后进入下一步execute
方法:
public <T> T execute(String url, HttpMethod method, @Nullable RequestCallback requestCallback,
@Nullable ResponseExtractor<T> responseExtractor, Map<String, ?> uriVariables)
throws RestClientException {
URI expanded = getUriTemplateHandler().expand(url, uriVariables);
return doExecute(expanded, method, requestCallback, responseExtractor);
}
在这里它只作了一个工作,根据urlVariables
中的键值对,替换url中的占位符,并转换为URI对象,然后进入方法doExecute
,这一步是它的核心逻辑所在:
protected <T> T doExecute(URI url, @Nullable HttpMethod method, @Nullable RequestCallback requestCallback,
@Nullable ResponseExtractor<T> responseExtractor) throws RestClientException {
Assert.notNull(url, "URI is required");
Assert.notNull(method, "HttpMethod is required");
ClientHttpResponse response = null;
try {
ClientHttpRequest request = createRequest(url, method);
if (requestCallback != null) {
requestCallback.doWithRequest(request);
}
response = request.execute();
handleResponse(url, method, response);
return (responseExtractor != null ? responseExtractor.extractData(response) : null);
}
catch (IOException ex) {
String resource = url.toString();
String query = url.getRawQuery();
resource = (query != null ? resource.substring(0, resource.indexOf('?')) : resource);
throw new ResourceAccessException("I/O error on " + method.name() +
" request for \"" + resource + "\": " + ex.getMessage(), ex);
}
finally {
if (response != null) {
response.close();
}
}
}
首先根据url和method参数创建Request对象,跟进方法查看:
protected ClientHttpRequest createRequest(URI url, HttpMethod method) throws IOException {
ClientHttpRequest request = getRequestFactory().createRequest(url, method);
// 这个initialize也是用来设置Request,默认什么操作都没有
initialize(request);
if (logger.isDebugEnabled()) {
logger.debug("HTTP " + method.name() + " " + url);
}
return request;
}
可以看到它是调用了RequestFactory来创建Request对象,而RequestFactory这个属性有一个默认值,属性签名如下:
private ClientHttpRequestFactory requestFactory = new SimpleClientHttpRequestFactory()
进入它的createRequest
方法:
public ClientHttpRequest createRequest(URI uri, HttpMethod httpMethod) throws IOException {
HttpURLConnection connection = openConnection(uri.toURL(), this.proxy);
prepareConnection(connection, httpMethod.name());
if (this.bufferRequestBody) {
return new SimpleBufferingClientHttpRequest(connection, this.outputStreaming);
}
else {
return new SimpleStreamingClientHttpRequest(connection, this.chunkSize, this.outputStreaming);
}
}
可以看到它是用了JDK中的HttpUrlConnection来建立连接,获取返回值,而Request对象类型根据是否缓存ReqeustBody分为SimpleBufferingClientHttpRequest
和SimpleStreamingClientHttpRequest
两种类型,默认bufferRequestBody==true
,即默认Request类型为SimpleBufferingClientHttpRequest
。
回到上一步,在创建完请求后,在发送请求之前还需要设置请求头和请求体,即应用RequestCallback,然后调用execute
方法,这里即调用HttpUrlConnection来执行请求,它会返回一个SimpleClientHttpResponse
类型对象,接下来就需要处理这个返回值。
对于这个Response,首先是调用handleResponse
方法来判断请求是否有异常(根据状态码来判断):
protected void handleResponse(URI url, HttpMethod method, ClientHttpResponse response) throws IOException {
ResponseErrorHandler errorHandler = getErrorHandler();
boolean hasError = errorHandler.hasError(response);
if (logger.isDebugEnabled()) {
try {
int code = response.getRawStatusCode();
HttpStatus status = HttpStatus.resolve(code);
logger.debug("Response " + (status != null ? status : code));
}
catch (IOException ex) {
// ignore
}
}
if (hasError) {
errorHandler.handleError(url, method, response);
}
}
如果有异常则调用errorHandler
来处理,默认errorHandler
类型为DefaultResponseErrorHandler
,它的处理方法是抛出异常,如果这里抛出异常则执行流程结束,不会再解析返回值。
如果没有异常则调用responseExtractor
来抽取返回值或者响应头(header),对于GET
方法,默认的responseExtractor
类型是HttpMessageConverterExtractor
,它会转换response对象为指定的返回类型T
,之后返回这个转换后的对象出去即可以。
getForEntity
上面讲的是getForObject
方法,那么getForEntity
方法呢,其实他们的区别就是传入的ResponseExtractor
类型不同,getForObject
传入的是HttpMessageConverterExtractor<T>
, 而getForEntity
传入的是ResponseExtractor<ResponseEntity<T>>
,而这个ResponseExtractor<ResponseEntity<T>>
只是在HttpMessageConverterExtractor
上封装了一个转换操作,构造方法如下:
public ResponseEntityResponseExtractor(@Nullable Type responseType) {
if (responseType != null && Void.class != responseType) {
this.delegate = new HttpMessageConverterExtractor<>(responseType, getMessageConverters(), logger);
}
else {
this.delegate = null;
}
}
在extractData
方法里可以看到也只是把返回值T
包装在了ResponseEntity
对象里:
public ResponseEntity<T> extractData(ClientHttpResponse response) throws IOException {
if (this.delegate != null) {
T body = this.delegate.extractData(response);
return ResponseEntity.status(response.getRawStatusCode()).headers(response.getHeaders()).body(body);
}
else {
return ResponseEntity.status(response.getRawStatusCode()).headers(response.getHeaders()).build();
}
}
}
Post请求?
那么post方法呢?以postForObject
为例:
public <T> T postForObject(String url, @Nullable Object request, Class<T> responseType,
Map<String, ?> uriVariables) throws RestClientException {
RequestCallback requestCallback = httpEntityCallback(request, responseType);
HttpMessageConverterExtractor<T> responseExtractor =
new HttpMessageConverterExtractor<>(responseType, getMessageConverters(), logger);
return execute(url, HttpMethod.POST, requestCallback, responseExtractor, uriVariables);
}
它和get的主要区别就是RequestCallback
实际使用的类型是HttpEntityRequestCallback
,即写入请求头也写入请求体,其他并无二致。
其他
RestTemplate类图:
Get请求的活动图: