版本:Spring 5
一、源码解读
先从创建开始
RestTemplate restTemplate = new RestTemplate();
来看下 RestTemplate
的类图:
可知,当初始化RestTemplate
时候,同时会先生成HttpAccessor
、InterceptingHttpAccessor
和RestOperations
那么来看下这些父类和接口:
(1)HttpAccessor
Accessor:存取器
可以看到HttpAccessor
主要功能:
- 提供请求工厂
- 创建请求
public abstract class HttpAccessor {
// 默认请求工厂
private ClientHttpRequestFactory requestFactory = new SimpleClientHttpRequestFactory();
// 同样可以设置请求工厂
public void setRequestFactory(ClientHttpRequestFactory requestFactory) {
Assert.notNull(requestFactory, "ClientHttpRequestFactory must not be null");
this.requestFactory = requestFactory;
}
// 获取请求工厂
public ClientHttpRequestFactory getRequestFactory() {
return this.requestFactory;
}
// 创建请求
protected ClientHttpRequest createRequest(URI url, HttpMethod method) throws IOException {
ClientHttpRequest request = getRequestFactory().createRequest(url, method);
if (logger.isDebugEnabled()) {
logger.debug("Created " + method.name() + " request for \"" + url + "\"");
}
return request;
}
}
(2)InterceptingHttpAccessor
这个类主要提供:设置这个RestTemplate
的拦截器们
public abstract class InterceptingHttpAccessor extends HttpAccessor {
// 拦截器列表
private final List<ClientHttpRequestInterceptor> interceptors = new ArrayList<>();
// 拦截器工厂
@Nullable
private volatile ClientHttpRequestFactory interceptingRequestFactory;
// 设置拦截器
public void setInterceptors(List<ClientHttpRequestInterceptor> interceptors) {
// Take getInterceptors() List as-is when passed in here
if (this.interceptors != interceptors) {
this.interceptors.clear();
this.interceptors.addAll(interceptors);
AnnotationAwareOrderComparator.sort(this.interceptors);
}
}
// 获取拦截器列表
public List<ClientHttpRequestInterceptor> getInterceptors() {
return this.interceptors;
}
// 设置请求工厂
@Override
public void setRequestFactory(ClientHttpRequestFactory requestFactory) {
super.setRequestFactory(requestFactory);
this.interceptingRequestFactory = null;
}
// 获取工厂
// 若无拦截器,则返回父类的请求工厂; 若有拦截器,则返回自身的`InterceptingClientHttpRequestFactory`
@Override
public ClientHttpRequestFactory getRequestFactory() {
List<ClientHttpRequestInterceptor> interceptors = getInterceptors();
if (!CollectionUtils.isEmpty(interceptors)) {
ClientHttpRequestFactory factory = this.interceptingRequestFactory;
if (factory == null) {
factory = new InterceptingClientHttpRequestFactory(super.getRequestFactory(), interceptors);
this.interceptingRequestFactory = factory;
}
return factory;
}
else {
return super.getRequestFactory();
}
}
}
(3)RestOperations
这个接口主要提供对外服务。
public interface RestOperations {
// ... ...
}
二、RestTemplate
请求流程
按这个请求来展开:
restTemplate.getForObject("/ping", String.class);
先讲共同点,再讲分歧。
getForObject()
// RestTemplate.java
public <T> T getForObject(URI url, Class<T> responseType) throws RestClientException {
// 请求回调
RequestCallback requestCallback = acceptHeaderRequestCallback(responseType);
// 消息提取器
HttpMessageConverterExtractor<T> responseExtractor =
new HttpMessageConverterExtractor<>(responseType, getMessageConverters(), logger);
// 执行
return execute(url, HttpMethod.GET, requestCallback, responseExtractor);
}
execute()
// RestTemplate.java
public <T> T execute(URI url, HttpMethod method, @Nullable RequestCallback requestCallback,
@Nullable ResponseExtractor<T> responseExtractor) throws RestClientException {
return doExecute(url, method, requestCallback, responseExtractor);
}
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) {
// ...
}
finally {
if (response != null) {
response.close();
}
}
}
createRequest(url, method);
, 这里会出现不同的处理。
(1) createRequest(url, method);
不同的处理,主要是:有无拦截器
调用的工厂不同,处理也不同。
调用的是HttpAccessor
方法
// HttpAccessor.java
protected ClientHttpRequest createRequest(URI url, HttpMethod method) throws IOException {
// 这一步开始有不同
ClientHttpRequest request = getRequestFactory().createRequest(url, method);
if (logger.isDebugEnabled()) {
logger.debug("Created " + method.name() + " request for \"" + url + "\"");
}
return request;
}
当调用getRequestFactory()
时,调用的是InterceptingHttpAccessor
里的
// InterceptingHttpAccessor.java
public ClientHttpRequestFactory getRequestFactory() {
// 1.
List<ClientHttpRequestInterceptor> interceptors = getInterceptors();
if (!CollectionUtils.isEmpty(interceptors)) {
ClientHttpRequestFactory factory = this.interceptingRequestFactory;
if (factory == null) {
factory = new InterceptingClientHttpRequestFactory(super.getRequestFactory(), interceptors);
this.interceptingRequestFactory = factory;
}
return factory;
}
else {
return super.getRequestFactory();
}
}
可以看到若没有拦截器,则直接调用父类HttpAccessor
的方法:return super.getRequestFactory();
否则,new InterceptingClientHttpRequestFactory(super.getRequestFactory(), interceptors);
1)new InterceptingClientHttpRequestFactory(super.getRequestFactory(), interceptors);
// InterceptingClientHttpRequestFactory.java
public InterceptingClientHttpRequestFactory(ClientHttpRequestFactory requestFactory,
@Nullable List<ClientHttpRequestInterceptor> interceptors) {
super(requestFactory);
this.interceptors = (interceptors != null ? interceptors : Collections.emptyList());
}
// ClientHttpRequestFactory.java
ClientHttpRequest createRequest(URI uri, HttpMethod httpMethod) throws IOException;
// InterceptingClientHttpRequestFactory.java
@Override
protected ClientHttpRequest createRequest(URI uri, HttpMethod httpMethod, ClientHttpRequestFactory requestFactory) {
return new InterceptingClientHttpRequest(requestFactory, this.interceptors, uri, httpMethod);
}
以上是创建过程,ClientHttpRequest
创建完成。
下面是执行过程 request.execute();
// RestTemplate.java
response = request.execute();
// ClientHttpRequest.java
public interface ClientHttpRequest extends HttpRequest, HttpOutputMessage {
ClientHttpResponse execute() throws IOException;
}
// AbstractClientHttpRequest.java
public final ClientHttpResponse execute() throws IOException {
assertNotExecuted();
// 重点
ClientHttpResponse result = executeInternal(this.headers);
this.executed = true;
return result;
}
executeInternal(this.headers);
// AbstractClientHttpRequest.java
protected abstract ClientHttpResponse executeInternal(HttpHeaders headers) throws IOException;
@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;
}
选择跳转到 InterceptingClientHttpRequest.java
protected final ClientHttpResponse executeInternal(HttpHeaders headers, byte[] bufferedOutput) throws IOException {
// 创建内部类
InterceptingRequestExecution requestExecution = new InterceptingRequestExecution();
// 内部类执行方法
return requestExecution.execute(this, bufferedOutput);
}
private class InterceptingRequestExecution implements ClientHttpRequestExecution {
private final Iterator<ClientHttpRequestInterceptor> iterator;
public InterceptingRequestExecution() {
this.iterator = interceptors.iterator();
}
@Override
public ClientHttpResponse execute(HttpRequest request, byte[] body) throws IOException {
// 这里就一层层调用拦截器
if (this.iterator.hasNext()) {
ClientHttpRequestInterceptor nextInterceptor = this.iterator.next();
return nextInterceptor.intercept(request, body, this);
}
else {
HttpMethod method = request.getMethod();
Assert.state(method != null, "No standard HTTP method");
ClientHttpRequest delegate = requestFactory.createRequest(request.getURI(), method);
request.getHeaders().forEach((key, value) -> delegate.getHeaders().addAll(key, value));
if (body.length > 0) {
if (delegate instanceof StreamingHttpOutputMessage) {
StreamingHttpOutputMessage streamingOutputMessage = (StreamingHttpOutputMessage) delegate;
streamingOutputMessage.setBody(outputStream -> StreamUtils.copy(body, outputStream));
}
else {
StreamUtils.copy(body, delegate.getBody());
}
}
return delegate.execute();
}
}
}
2)return super.getRequestFactory();
这个直接返回父类已经初始化好的 SimpleClientHttpRequestFactory
private ClientHttpRequestFactory requestFactory = new SimpleClientHttpRequestFactory();
public ClientHttpRequestFactory getRequestFactory() {
return this.requestFactory;
}
之后跟上面思路类似
三、问题
(1)什么时候注入ClientHttpRequestInterceptor
?
创建RestTemplate
时候,可以设置。
public class RestTemplateHeaderModifierInterceptor
implements ClientHttpRequestInterceptor {
@Override
public ClientHttpResponse intercept(
HttpRequest request,
byte[] body,
ClientHttpRequestExecution execution) throws IOException {
ClientHttpResponse response = execution.execute(request, body);
response.getHeaders().add("Foo", "bar");
return response;
}
}
@Configuration
public class RestClientConfig {
@Bean
public RestTemplate restTemplate() {
RestTemplate restTemplate = new RestTemplate();
List<ClientHttpRequestInterceptor> interceptors
= restTemplate.getInterceptors();
if (CollectionUtils.isEmpty(interceptors)) {
interceptors = new ArrayList<>();
}
// 这边多添加一个自己自定义的
interceptors.add(new RestTemplateHeaderModifierInterceptor());
restTemplate.setInterceptors(interceptors);
return restTemplate;
}
}
(2)RestTemplate
模板体现在哪?
模板体现在统一处理吧,如异常等。
但凡凡好像没找到诶。
四、凡凡有话说
希望能提高阅读代码的能力吧。
下面是凡凡自己的看法:
看到一半这个RestTemplate
设计的并不是很好。
RestTemplate
和InterceptingHttpAccessor
并没有直接关系
如果可以采用组合方式或许更好。
来谈谈RestTemplate
的职责吧:1. 对外提供方法 2. 转交处理请求
那么RestTemplate
更像是一个工具人
- 有时虽然遵守
LSP
原则,但增加阅读源码的难度。
Debug可能好些,但凡凡好像太弱了,debug一直找不到自己想要的,所以就肉眼了。
五、参考资料
https://www.baeldung.com/spring-rest-template-interceptor