【Spring】之 RestTemplate浅析

版本:Spring 5


一、源码解读


先从创建开始
RestTemplate restTemplate = new RestTemplate();

来看下 RestTemplate的类图:
在这里插入图片描述

可知,当初始化RestTemplate时候,同时会先生成HttpAccessorInterceptingHttpAccessorRestOperations

那么来看下这些父类和接口:


(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);

先讲共同点,再讲分歧。

  1. 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);
}
  1. 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设计的并不是很好。

  1. RestTemplateInterceptingHttpAccessor 并没有直接关系

如果可以采用组合方式或许更好。
来谈谈RestTemplate的职责吧:1. 对外提供方法 2. 转交处理请求
那么 RestTemplate更像是一个工具人

  1. 有时虽然遵守 LSP 原则,但增加阅读源码的难度。

Debug可能好些,但凡凡好像太弱了,debug一直找不到自己想要的,所以就肉眼了。



五、参考资料


https://www.baeldung.com/spring-rest-template-interceptor

发布了404 篇原创文章 · 获赞 270 · 访问量 42万+

猜你喜欢

转载自blog.csdn.net/fanfan4569/article/details/102525907