版本: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