RestTemplate封装HTTP基础请求实现,额外提供拦截扩展能力。基于此扩展能力,Ribbon、LoadBalancer实现负载均衡调用,Feign进一步依赖负载均衡组件提供声明式接口,抽象简化开发。所以,探索RestTemplate实现原理与调用流程,才能深入理解负载均衡、网关实现原理。
01 类结构
从类结构可以看出,RestTemplate非常符合Spring设计规范,继承抽象类InterceptingHttpAccessor,实现RestOperations接口。

02 执行流程图
以RestTemplate#getForObject方法为例分析整体执行流程,包括执行流程、涉及关键组件以及核心扩展点,用于后期设计时重点关注项。

03 RestTemplate源码剖析
3.1 构造器
属性 | 作用 |
---|---|
List interceptors | 请求拦截器 |
ClientHttpRequestFactory interceptingRequestFactory | 创建请求工厂 |
List<HttpMessageConverter<?>> messageConverters | 数据转换器 |
ResponseErrorHandler errorHandler | 响应异常处理器 |
ResponseExtractor headersExtractor | 响应头处理器 |
java
public abstract class HttpAccessor {
// 请求创建工厂
private ClientHttpRequestFactory requestFactory = new SimpleClientHttpRequestFactory();
// 客户端请求初始化
private final List<ClientHttpRequestInitializer> clientHttpRequestInitializers = new ArrayList<>();
}
public abstract class InterceptingHttpAccessor extends HttpAccessor {
// 客户端请求拦截器
private final List<ClientHttpRequestInterceptor> interceptors = new ArrayList<>();
// 客户端请求创建工厂
private volatile ClientHttpRequestFactory interceptingRequestFactory;
}
java
public class RestTemplate extends InterceptingHttpAccessor implements RestOperations {
private static final boolean romePresent;
private static final boolean jaxb2Present;
private static final boolean jackson2Present;
private static final boolean jackson2XmlPresent;
private static final boolean jackson2SmilePresent;
private static final boolean jackson2CborPresent;
private static final boolean gsonPresent;
private static final boolean jsonbPresent;
static {
ClassLoader classLoader = RestTemplate.class.getClassLoader();
romePresent = ClassUtils.isPresent("com.rometools.rome.feed.WireFeed", classLoader);
jaxb2Present = ClassUtils.isPresent("javax.xml.bind.Binder", classLoader);
jackson2Present = ClassUtils.isPresent("com.fasterxml.jackson.databind.ObjectMapper", classLoader)
&& ClassUtils.isPresent("com.fasterxml.jackson.core.JsonGenerator", classLoader);
jackson2XmlPresent = ClassUtils.isPresent("com.fasterxml.jackson.dataformat.xml.XmlMapper", classLoader);
jackson2SmilePresent = ClassUtils.isPresent("com.fasterxml.jackson.dataformat.smile.SmileFactory", classLoader);
jackson2CborPresent = ClassUtils.isPresent("com.fasterxml.jackson.dataformat.cbor.CBORFactory", classLoader);
gsonPresent = ClassUtils.isPresent("com.google.gson.Gson", classLoader);
jsonbPresent = ClassUtils.isPresent("javax.json.bind.Jsonb", classLoader);
}
// 类型转换器
private final List<HttpMessageConverter<?>> messageConverters = new ArrayList<>();
// 响应异常处理
private ResponseErrorHandler errorHandler = new DefaultResponseErrorHandler();
// URI模板处理器: 构建URI
private UriTemplateHandler uriTemplateHandler;
// 响应结果处理
private final ResponseExtractor<HttpHeaders> headersExtractor = new HeadersExtractor();
public RestTemplate() {
// 类型转换器
this.messageConverters.add(new ByteArrayHttpMessageConverter());
this.messageConverters.add(new StringHttpMessageConverter());
this.messageConverters.add(new ResourceHttpMessageConverter(false));
try {
this.messageConverters.add(new SourceHttpMessageConverter<>());
} catch (Error err) {
// Ignore when no TransformerFactory implementation is available
}
this.messageConverters.add(new AllEncompassingFormHttpMessageConverter());
if (romePresent) {
this.messageConverters.add(new AtomFeedHttpMessageConverter());
this.messageConverters.add(new RssChannelHttpMessageConverter());
}
if (jackson2XmlPresent) {
this.messageConverters.add(new MappingJackson2XmlHttpMessageConverter());
} else if (jaxb2Present) {
this.messageConverters.add(new Jaxb2RootElementHttpMessageConverter());
}
if (jackson2Present) {
this.messageConverters.add(new MappingJackson2HttpMessageConverter());
} else if (gsonPresent) {
this.messageConverters.add(new GsonHttpMessageConverter());
} else if (jsonbPresent) {
this.messageConverters.add(new JsonbHttpMessageConverter());
}
if (jackson2SmilePresent) {
this.messageConverters.add(new MappingJackson2SmileHttpMessageConverter());
}
if (jackson2CborPresent) {
this.messageConverters.add(new MappingJackson2CborHttpMessageConverter());
}
// 初始化URI构建处理器
this.uriTemplateHandler = initUriTemplateHandler();
}
private static DefaultUriBuilderFactory initUriTemplateHandler() {
DefaultUriBuilderFactory uriFactory = new DefaultUriBuilderFactory();
// URI非ASCII和非法字符转义
uriFactory.setEncodingMode(EncodingMode.URI_COMPONENT);
return uriFactory;
}
}
3.2 getForObject
java
public class RestTemplate extends InterceptingHttpAccessor implements RestOperations {
@Override
public <T> T getForObject(String url, Class<T> responseType, Object... uriVariables) throws RestClientException {
RequestCallback requestCallback = acceptHeaderRequestCallback(responseType);
// 响应数据转换与数据提取
HttpMessageConverterExtractor<T> responseExtractor = new HttpMessageConverterExtractor<>(responseType, getMessageConverters(), logger);
// 发送GET请求
return execute(url, HttpMethod.GET, requestCallback, responseExtractor, uriVariables);
}
// 接收请求头回调
public <T> RequestCallback acceptHeaderRequestCallback(Class<T> responseType) {
return new AcceptHeaderRequestCallback(responseType);
}
}
3.3 execute
java
public class RestTemplate extends InterceptingHttpAccessor implements RestOperations {
@Override
@Nullable
public <T> T execute(String url, HttpMethod method, @Nullable RequestCallback requestCallback,
@Nullable ResponseExtractor<T> responseExtractor, Object... uriVariables) throws RestClientException {
// 获取URI参数
URI expanded = getUriTemplateHandler().expand(url, uriVariables);
// 执行调用
return doExecute(expanded, method, requestCallback, responseExtractor);
}
public UriTemplateHandler getUriTemplateHandler() {
return this.uriTemplateHandler;
}
}
3.4 doExecute
java
public class RestTemplate extends InterceptingHttpAccessor implements RestOperations {
@Nullable
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 = super.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();
}
}
}
}
3.5 super.createRequest
创建客户群请求,如果拦截器(ClientHttpRequestInterceptor)不为空,就会创建拦截客户端请求工厂(InterceptingClientHttpRequestFactory)。
java
public abstract class HttpAccessor {
// 请求创建工厂
private ClientHttpRequestFactory requestFactory = new SimpleClientHttpRequestFactory();
// 初始化
private final List<ClientHttpRequestInitializer> clientHttpRequestInitializers = new ArrayList<>();
protected ClientHttpRequest createRequest(URI url, HttpMethod method) throws IOException {
ClientHttpRequest request = getRequestFactory().createRequest(url, method);
initialize(request);
if (logger.isDebugEnabled()) {
logger.debug("HTTP " + method.name() + " " + url);
}
return request;
}
public ClientHttpRequestFactory getRequestFactory() {
return this.requestFactory;
}
// 初始化请求
private void initialize(ClientHttpRequest request) {
this.clientHttpRequestInitializers.forEach(initializer -> initializer.initialize(request));
}
}
public abstract class InterceptingHttpAccessor extends HttpAccessor {
// 拦截器
private final List<ClientHttpRequestInterceptor> interceptors = new ArrayList<>();
// 客户端创建工厂
private volatile ClientHttpRequestFactory interceptingRequestFactory;
@Override
public ClientHttpRequestFactory getRequestFactory() {
// 获取拦截器
List<ClientHttpRequestInterceptor> interceptors = getInterceptors();
if (!CollectionUtils.isEmpty(interceptors)) {
// 请求创建工厂
ClientHttpRequestFactory factory = this.interceptingRequestFactory;
// 为空创建: 类似CopyOnWrite机制
if (factory == null) {
factory = new InterceptingClientHttpRequestFactory(super.getRequestFactory(), interceptors);
this.interceptingRequestFactory = factory;
}
return factory;
}
return super.getRequestFactory();
}
public List<ClientHttpRequestInterceptor> getInterceptors() {
return this.interceptors;
}
}
3.6 handleResponse
java
public class RestTemplate extends InterceptingHttpAccessor implements RestOperations {
// 请求异常处理
private ResponseErrorHandler errorHandler = new DefaultResponseErrorHandler();
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);
}
}
public ResponseErrorHandler getErrorHandler() {
return this.errorHandler;
}
}
04 DefaultUriBuilderFactory
DefaultUriBuilderFactory提供URI构造支持,可以添加各种请求路径参数,内部通过DefaultUriBuilder进行URI处理。

java
public interface UriTemplateHandler {
URI expand(String uriTemplate, Map<String, ?> uriVariables);
URI expand(String uriTemplate, Object... uriVariables);
}
public interface UriBuilderFactory extends UriTemplateHandler {
UriBuilder uriString(String uriTemplate);
UriBuilder builder();
}
java
public class DefaultUriBuilderFactory implements UriBuilderFactory {
// 公共URI
private final UriComponentsBuilder baseUri;
// 编码模式
private EncodingMode encodingMode = EncodingMode.TEMPLATE_AND_VALUES;
// 默认变量参数
private final Map<String, Object> defaultUriVariables = new HashMap<>();
// 是否编码/
private boolean parsePath = true;
public DefaultUriBuilderFactory() {
this.baseUri = null;
}
public DefaultUriBuilderFactory(String baseUriTemplate) {
this.baseUri = UriComponentsBuilder.fromUriString(baseUriTemplate);
}
public void setDefaultUriVariables(@Nullable Map<String, ?> defaultUriVariables) {
this.defaultUriVariables.clear();
if (defaultUriVariables != null) {
this.defaultUriVariables.putAll(defaultUriVariables);
}
}
@Override
public URI expand(String uriTemplate, Map<String, ?> uriVars) {
return uriString(uriTemplate).build(uriVars);
}
@Override
public URI expand(String uriTemplate, Object... uriVars) {
return uriString(uriTemplate).build(uriVars);
}
@Override
public UriBuilder uriString(String uriTemplate) {
return new DefaultUriBuilder(uriTemplate);
}
@Override
public UriBuilder builder() {
return new DefaultUriBuilder("");
}
}
05 RequestCallback
ClientHttpRequest#doWithRequest方法用于设置请求头信息,主要包括AcceptHeaderRequestCallback与HttpEntityRequestCallback两个实现类。

5.1 AcceptHeaderRequestCallback
AcceptHeaderRequestCallback获取消息转换器(HttpMessageConverter)支持转换类型,排序设置请求头接收数据类型。
java
private class AcceptHeaderRequestCallback implements RequestCallback {
@Nullable
private final Type responseType;
public AcceptHeaderRequestCallback(@Nullable Type responseType) {
this.responseType = responseType;
}
@Override
public void doWithRequest(ClientHttpRequest request) throws IOException {
if (this.responseType != null) {
// 获取类型转换器
List<MediaType> allSupportedMediaTypes = getMessageConverters().stream()
.filter(converter -> canReadResponse(this.responseType, converter))
.flatMap(this::getSupportedMediaTypes)
.distinct()
.sorted(MediaType.SPECIFICITY_COMPARATOR)
.collect(Collectors.toList());
if (logger.isDebugEnabled()) {
logger.debug("Accept=" + allSupportedMediaTypes);
}
// 设置接收数据类型
request.getHeaders().setAccept(allSupportedMediaTypes);
}
}
private boolean canReadResponse(Type responseType, HttpMessageConverter<?> converter) {
Class<?> responseClass = (responseType instanceof Class ? (Class<?>) responseType : null);
// 判断当前转换器是否支持
if (responseClass != null) {
return converter.canRead(responseClass, null);
} else if (converter instanceof GenericHttpMessageConverter) {
GenericHttpMessageConverter<?> genericConverter = (GenericHttpMessageConverter<?>) converter;
return genericConverter.canRead(responseType, null, null);
}
return false;
}
// 获取支持的媒体类型
private Stream<MediaType> getSupportedMediaTypes(HttpMessageConverter<?> messageConverter) {
return messageConverter.getSupportedMediaTypes().stream()
.map(mediaType -> {
if (mediaType.getCharset() != null) {
return new MediaType(mediaType.getType(), mediaType.getSubtype());
}
return mediaType;
});
}
}
5.2 HttpEntityRequestCallback
AcceptHeaderRequestCallback不仅需要根据消息转换器(HttpMessageConverter)支持转换类型设置接收数据类型,还需要请求体缓冲区写入请求参数内容。
java
private class HttpEntityRequestCallback extends AcceptHeaderRequestCallback {
private final HttpEntity<?> requestEntity;
public HttpEntityRequestCallback(@Nullable Object requestBody) {
this(requestBody, null);
}
public HttpEntityRequestCallback(@Nullable Object requestBody, @Nullable Type responseType) {
super(responseType);
if (requestBody instanceof HttpEntity) {
this.requestEntity = (HttpEntity<?>) requestBody;
} else if (requestBody != null) {
this.requestEntity = new HttpEntity<>(requestBody);
} else {
this.requestEntity = HttpEntity.EMPTY;
}
}
@Override
@SuppressWarnings("unchecked")
public void doWithRequest(ClientHttpRequest httpRequest) throws IOException {
super.doWithRequest(httpRequest);
// 请求体
Object requestBody = this.requestEntity.getBody();
if (requestBody == null) {
// 获取请求头
HttpHeaders httpHeaders = httpRequest.getHeaders();
HttpHeaders requestHeaders = this.requestEntity.getHeaders();
// 设置请求头
if (!requestHeaders.isEmpty()) {
requestHeaders.forEach((key, values) -> httpHeaders.put(key, new ArrayList<>(values)));
}
if (httpHeaders.getContentLength() < 0) {
httpHeaders.setContentLength(0L);
}
} else {
Class<?> requestBodyClass = requestBody.getClass();
// 请求体类型
Type requestBodyType = (this.requestEntity instanceof RequestEntity ? ((RequestEntity<?>)this.requestEntity).getType() : requestBodyClass);
// 请求头
HttpHeaders httpHeaders = httpRequest.getHeaders();
HttpHeaders requestHeaders = this.requestEntity.getHeaders();
// 请求头: ContentType
MediaType requestContentType = requestHeaders.getContentType();
// 设置接收
for (HttpMessageConverter<?> messageConverter : getMessageConverters()) {
if (messageConverter instanceof GenericHttpMessageConverter) {
GenericHttpMessageConverter<Object> genericConverter = (GenericHttpMessageConverter<Object>) messageConverter;
if (genericConverter.canWrite(requestBodyType, requestBodyClass, requestContentType)) {
if (!requestHeaders.isEmpty()) {
requestHeaders.forEach((key, values) -> httpHeaders.put(key, new ArrayList<>(values)));
}
logBody(requestBody, requestContentType, genericConverter);
// 发送请求体
genericConverter.write(requestBody, requestBodyType, requestContentType, httpRequest);
return;
}
} else if (messageConverter.canWrite(requestBodyClass, requestContentType)) {
if (!requestHeaders.isEmpty()) {
requestHeaders.forEach((key, values) -> httpHeaders.put(key, new ArrayList<>(values)));
}
logBody(requestBody, requestContentType, messageConverter);
// 发送请求体
((HttpMessageConverter<Object>) messageConverter).write(requestBody, requestContentType, httpRequest);
return;
}
}
String message = "No HttpMessageConverter for " + requestBodyClass.getName();
if (requestContentType != null) {
message += " and content type "" + requestContentType + """;
}
throw new RestClientException(message);
}
}
private void logBody(Object body, @Nullable MediaType mediaType, HttpMessageConverter<?> converter) {
if (logger.isDebugEnabled()) {
if (mediaType != null) {
logger.debug("Writing [" + body + "] as "" + mediaType + """);
} else {
logger.debug("Writing [" + body + "] with " + converter.getClass().getName());
}
}
}
}
06 ResponseExtractor
ResponseExtractor用于响应提取数据类型处理,提供实现类HttpMessageConverterExtractor、HeadersExtractor和ResponseEntityResponseExtractor。

java
public interface ResponseExtractor<T> {
@Nullable
T extractData(ClientHttpResponse response) throws IOException;
}
6.1 HttpMessageConverterExtractor
HttpMessageConverterExtractor直接根据服务器响应请求头ContentType与目标数据类型,判断消息转换器是否支持转换,支持则进行转换范围数据。
java
public class HttpMessageConverterExtractor<T> implements ResponseExtractor<T> {
// 响应类型
private final Type responseType;
@Nullable
private final Class<T> responseClass;
// 消息转换器
private final List<HttpMessageConverter<?>> messageConverters;
public HttpMessageConverterExtractor(Class<T> responseType, List<HttpMessageConverter<?>> messageConverters) {
this((Type) responseType, messageConverters);
}
public HttpMessageConverterExtractor(Type responseType, List<HttpMessageConverter<?>> messageConverters) {
this(responseType, messageConverters, LogFactory.getLog(HttpMessageConverterExtractor.class));
}
@SuppressWarnings("unchecked")
HttpMessageConverterExtractor(Type responseType, List<HttpMessageConverter<?>> messageConverters, Log logger) {
this.responseType = responseType;
this.responseClass = (responseType instanceof Class ? (Class<T>) responseType : null);
this.messageConverters = messageConverters;
}
@Override
@SuppressWarnings({"unchecked", "rawtypes", "resource"})
public T extractData(ClientHttpResponse response) throws IOException {
MessageBodyClientHttpResponseWrapper responseWrapper = new MessageBodyClientHttpResponseWrapper(response);
// 没有响应
if (!responseWrapper.hasMessageBody() || responseWrapper.hasEmptyMessageBody()) {
return null;
}
// 获取响应数据类型
MediaType contentType = getContentType(responseWrapper);
try {
// 执行数据转换
for (HttpMessageConverter<?> messageConverter : this.messageConverters) {
if (messageConverter instanceof GenericHttpMessageConverter) {
GenericHttpMessageConverter<?> genericMessageConverter =
(GenericHttpMessageConverter<?>) messageConverter;
if (genericMessageConverter.canRead(this.responseType, null, contentType)) {
return (T) genericMessageConverter.read(this.responseType, null, responseWrapper);
}
}
if (this.responseClass != null) {
if (messageConverter.canRead(this.responseClass, contentType)) {
return (T) messageConverter.read((Class) this.responseClass, responseWrapper);
}
}
}
} catch (IOException | HttpMessageNotReadableException ex) {
throw new RestClientException("Error while extracting response for type [" + this.responseType + "] and content type [" + contentType + "]", ex);
}
throw new UnknownContentTypeException(...);
}
protected MediaType getContentType(ClientHttpResponse response) {
MediaType contentType = response.getHeaders().getContentType();
if (contentType == null) {
contentType = MediaType.APPLICATION_OCTET_STREAM;
}
return contentType;
}
private static byte[] getResponseBody(ClientHttpResponse response) {
try {
return FileCopyUtils.copyToByteArray(response.getBody());
} catch (IOException ex) {
// ignore
}
return new byte[0];
}
}
6.2 HeadersExtractor
HeadersExtractor仅仅提取服务端响应头数据类型,所以不需要额外处理。
java
private static class HeadersExtractor implements ResponseExtractor<HttpHeaders> {
@Override
public HttpHeaders extractData(ClientHttpResponse response) {
return response.getHeaders();
}
}
6.3 ResponseEntityResponseExtractor
ResponseEntityResponseExtractor底层委托HttpMessageConverterExtractor进行数据转换,提取响应状态码、响应头与消息体封装为ResponseEntity进行返回。
java
private class ResponseEntityResponseExtractor<T> implements ResponseExtractor<ResponseEntity<T>> {
@Nullable
private final HttpMessageConverterExtractor<T> delegate;
public ResponseEntityResponseExtractor(@Nullable Type responseType) {
if (responseType != null && Void.class != responseType) {
this.delegate = new HttpMessageConverterExtractor<>(responseType, getMessageConverters(), logger);
} else {
this.delegate = null;
}
}
@Override
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);
}
return ResponseEntity.status(response.getRawStatusCode()).headers(response.getHeaders()).build();
}
}
07 ClientHttpRequestFactory
ClientHttpRequestFactory用于根据URI和请求方法(HttpMethod)创建客户群请求,提供多种工具类客户端请求封装,比较经典主要包括JDK HttpURLConnection 、Apache HttpComponents 或者okHttp 等工具类实现,其次就是针对拦截器提供的InterceptingClientHttpRequestFactory。

java
public interface ClientHttpRequestFactory {
ClientHttpRequest createRequest(URI uri, HttpMethod httpMethod) throws IOException;
}
public interface ClientHttpRequest extends HttpRequest, HttpOutputMessage {
ClientHttpResponse execute() throws IOException;
}
7.1 SimpleClientHttpRequestFactory
SimpleClientHttpRequestFactory用于创建JDK HttpURLConnection客户端请求,同时还会设置链接默认参数。
java
public class SimpleClientHttpRequestFactory implements ClientHttpRequestFactory, AsyncClientHttpRequestFactory {
// 默认数据块大小
private static final int DEFAULT_CHUNK_SIZE = 4096;
// 代理
private Proxy proxy;
// 是否开启请求体缓冲区
private boolean bufferRequestBody = true;
// 数据块大小
private int chunkSize = DEFAULT_CHUNK_SIZE;
// 链接超时
private int connectTimeout = -1;
// 读取超时
private int readTimeout = -1;
// 是否流数据
private boolean outputStreaming = true;
// 执行器
private AsyncListenableTaskExecutor taskExecutor;
@Override
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);
}
return new SimpleStreamingClientHttpRequest(connection, this.chunkSize, this.outputStreaming);
}
protected void prepareConnection(HttpURLConnection connection, String httpMethod) throws IOException {
if (this.connectTimeout >= 0) {
connection.setConnectTimeout(this.connectTimeout);
}
if (this.readTimeout >= 0) {
connection.setReadTimeout(this.readTimeout);
}
connection.setDoInput(true);
if ("GET".equals(httpMethod)) {
connection.setInstanceFollowRedirects(true);
} else {
connection.setInstanceFollowRedirects(false);
}
if ("POST".equals(httpMethod) || "PUT".equals(httpMethod) || "PATCH".equals(httpMethod) || "DELETE".equals(httpMethod)) {
connection.setDoOutput(true);
} else {
connection.setDoOutput(false);
}
connection.setRequestMethod(httpMethod);
}
}
7.2 InterceptingClientHttpRequestFactory
java
public class InterceptingClientHttpRequestFactory extends AbstractClientHttpRequestFactoryWrapper {
// 拦截器
private final List<ClientHttpRequestInterceptor> interceptors;
public InterceptingClientHttpRequestFactory(ClientHttpRequestFactory requestFactory,
@Nullable List<ClientHttpRequestInterceptor> interceptors) {
super(requestFactory);
this.interceptors = (interceptors != null ? interceptors : Collections.emptyList());
}
@Override
protected ClientHttpRequest createRequest(URI uri, HttpMethod httpMethod, ClientHttpRequestFactory requestFactory) {
return new InterceptingClientHttpRequest(requestFactory, this.interceptors, uri, httpMethod);
}
}
08 ClientHttpRequest
ClientHttpRequest用于封装客户端HTTP请求,然后返回服务器响应ClientHttpResponse封装数据。封装很多实现类,包括JDK HttpURLConnection 、Apache HttpComponents 或者okHttp等工具实现,还有就是拦截器实现类InterceptingClientHttpRequest。

java
public interface ClientHttpRequest extends HttpRequest, HttpOutputMessage {
ClientHttpResponse execute() throws IOException;
}
8.1 抽象客户端请求
java
public abstract class AbstractClientHttpRequest implements ClientHttpRequest {
private final HttpHeaders headers = new HttpHeaders();
private boolean executed = false;
@Override
public final HttpHeaders getHeaders() {
return (this.executed ? HttpHeaders.readOnlyHttpHeaders(this.headers) : this.headers);
}
@Override
public final OutputStream getBody() throws IOException {
assertNotExecuted();
return getBodyInternal(this.headers);
}
@Override
public final ClientHttpResponse execute() throws IOException {
assertNotExecuted();
ClientHttpResponse result = executeInternal(this.headers);
this.executed = true;
return result;
}
protected void assertNotExecuted() {
Assert.state(!this.executed, "ClientHttpRequest already executed");
}
protected abstract OutputStream getBodyInternal(HttpHeaders headers) throws IOException;
protected abstract ClientHttpResponse executeInternal(HttpHeaders headers) throws IOException;
}
abstract class AbstractBufferingClientHttpRequest extends AbstractClientHttpRequest {
private ByteArrayOutputStream bufferedOutput = new ByteArrayOutputStream(1024);
@Override
protected OutputStream getBodyInternal(HttpHeaders headers) throws IOException {
return this.bufferedOutput;
}
@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;
}
protected abstract ClientHttpResponse executeInternal(HttpHeaders headers, byte[] bufferedOutput) throws IOException;
}
8.2 SimpleBufferingAsyncClientHttpRequest
SimpleBufferingAsyncClientHttpRequest属于JDK HttpURLConnection模式客户端请求,属于一次性读取全部数据。
java
final class SimpleBufferingAsyncClientHttpRequest extends AbstractBufferingAsyncClientHttpRequest {
// HTTP链接
private final HttpURLConnection connection;
// 是否流式数据
private final boolean outputStreaming;
// 线程池处理器
private final AsyncListenableTaskExecutor taskExecutor;
SimpleBufferingAsyncClientHttpRequest(HttpURLConnection connection, boolean outputStreaming, AsyncListenableTaskExecutor taskExecutor) {
this.connection = connection;
this.outputStreaming = outputStreaming;
this.taskExecutor = taskExecutor;
}
@Override
public String getMethodValue() {
return this.connection.getRequestMethod();
}
@Override
public URI getURI() {
try {
return this.connection.getURL().toURI();
} catch (URISyntaxException ex) {
throw new IllegalStateException("Could not get HttpURLConnection URI: " + ex.getMessage(), ex);
}
}
@Override
protected ListenableFuture<ClientHttpResponse> executeInternal(final HttpHeaders headers, final byte[] bufferedOutput) throws IOException {
return this.taskExecutor.submitListenable(new Callable<ClientHttpResponse>() {
@Override
public ClientHttpResponse call() throws Exception {
// 添加请求头
SimpleBufferingClientHttpRequest.addHeaders(connection, headers);
// JDK <1.8 doesn't support getOutputStream with HTTP DELETE
if (getMethod() == HttpMethod.DELETE && bufferedOutput.length == 0) {
connection.setDoOutput(false);
}
if (connection.getDoOutput() && outputStreaming) {
connection.setFixedLengthStreamingMode(bufferedOutput.length);
}
// 打开链接: 执行请求的意思
connection.connect();
if (connection.getDoOutput()) {
// 拷贝数据
FileCopyUtils.copy(bufferedOutput, connection.getOutputStream());
} else {
// Immediately trigger the request in a no-output scenario as well
connection.getResponseCode();
}
return new SimpleClientHttpResponse(connection);
}
});
}
}
8.3 SimpleStreamingAsyncClientHttpRequest
SimpleBufferingAsyncClientHttpRequest属于JDK HttpURLConnection模式客户端请求,属于分块读取服务端数据。
java
final class SimpleStreamingAsyncClientHttpRequest extends AbstractAsyncClientHttpRequest {
private final HttpURLConnection connection;
private final int chunkSize;
private OutputStream body;
private final boolean outputStreaming;
private final AsyncListenableTaskExecutor taskExecutor;
SimpleStreamingAsyncClientHttpRequest(HttpURLConnection connection, int chunkSize, boolean outputStreaming, AsyncListenableTaskExecutor taskExecutor) {
this.connection = connection;
this.chunkSize = chunkSize;
this.outputStreaming = outputStreaming;
this.taskExecutor = taskExecutor;
}
@Override
public String getMethodValue() {
return this.connection.getRequestMethod();
}
@Override
public URI getURI() {
try {
return this.connection.getURL().toURI();
} catch (URISyntaxException ex) {
throw new IllegalStateException("Could not get HttpURLConnection URI: " + ex.getMessage(), ex);
}
}
@Override
protected OutputStream getBodyInternal(HttpHeaders headers) throws IOException {
if (this.body == null) {
if (this.outputStreaming) {
long contentLength = headers.getContentLength();
if (contentLength >= 0) {
// 设置固定数据块大小
this.connection.setFixedLengthStreamingMode(contentLength);
} else {
this.connection.setChunkedStreamingMode(this.chunkSize);
}
}
// 添加请求头
SimpleBufferingClientHttpRequest.addHeaders(this.connection, headers);
this.connection.connect();
this.body = this.connection.getOutputStream();
}
return StreamUtils.nonClosing(this.body);
}
@Override
protected ListenableFuture<ClientHttpResponse> executeInternal(final HttpHeaders headers) throws IOException {
return this.taskExecutor.submitListenable(new Callable<ClientHttpResponse>() {
@Override
public ClientHttpResponse call() throws Exception {
try {
if (body != null) {
body.close();
} else {
SimpleBufferingClientHttpRequest.addHeaders(connection, headers);
connection.connect();
// Immediately trigger the request in a no-output scenario as well
connection.getResponseCode();
}
} catch (IOException ex) {
// ignore
}
return new SimpleClientHttpResponse(connection);
}
});
}
}
8.4 InterceptingClientHttpRequest
InterceptingClientHttpRequest封装拦截器调用,执行逻辑是首先调用拦截器方法,最后真正发送服务端请求获取数据。
java
class InterceptingClientHttpRequest extends AbstractBufferingClientHttpRequest {
// 客户端创建工厂
private final ClientHttpRequestFactory requestFactory;
// 拦截器
private final List<ClientHttpRequestInterceptor> interceptors;
// 请求方法
private HttpMethod method;
// 请求URI
private URI uri;
protected InterceptingClientHttpRequest(ClientHttpRequestFactory requestFactory,
List<ClientHttpRequestInterceptor> interceptors, URI uri, HttpMethod method) {
this.requestFactory = requestFactory;
this.interceptors = interceptors;
this.method = method;
this.uri = uri;
}
@Override
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);
}
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();
}
}
}
09 ResponseErrorHandler
ResponseErrorHandler 用于处理服务端响应错误,提供实现类DefaultResponseErrorHandler 和ExtractingResponseErrorHandler。
java
public interface ResponseErrorHandler {
// 是否存在错误
boolean hasError(ClientHttpResponse response) throws IOException;
// 处理错误
void handleError(ClientHttpResponse response) throws IOException;
// 处理错误
default void handleError(URI url, HttpMethod method, ClientHttpResponse response) throws IOException {
handleError(response);
}
}
9.1 DefaultResponseErrorHandler
java
public class DefaultResponseErrorHandler implements ResponseErrorHandler {
@Override
public boolean hasError(ClientHttpResponse response) throws IOException {
int rawStatusCode = response.getRawStatusCode();
HttpStatus statusCode = HttpStatus.resolve(rawStatusCode);
return (statusCode != null ? hasError(statusCode) : hasError(rawStatusCode));
}
protected boolean hasError(HttpStatus statusCode) {
return statusCode.isError();
}
protected boolean hasError(int unknownStatusCode) {
HttpStatus.Series series = HttpStatus.Series.resolve(unknownStatusCode);
return (series == HttpStatus.Series.CLIENT_ERROR || series == HttpStatus.Series.SERVER_ERROR);
}
@Override
public void handleError(ClientHttpResponse response) throws IOException {
HttpStatus statusCode = HttpStatus.resolve(response.getRawStatusCode());
if (statusCode == null) {
byte[] body = getResponseBody(response);
String message = getErrorMessage(response.getRawStatusCode(), response.getStatusText(), body, getCharset(response));
throw new UnknownHttpStatusCodeException(...);
}
handleError(response, statusCode);
}
private String getErrorMessage(int rawStatusCode, String statusText, @Nullable byte[] responseBody, @Nullable Charset charset) {
String preface = rawStatusCode + " " + statusText + ": ";
if (ObjectUtils.isEmpty(responseBody)) {
return preface + "[no body]";
}
charset = charset == null ? StandardCharsets.UTF_8 : charset;
int maxChars = 200;
if (responseBody.length < maxChars * 2) {
return preface + "[" + new String(responseBody, charset) + "]";
}
try {
Reader reader = new InputStreamReader(new ByteArrayInputStream(responseBody), charset);
CharBuffer buffer = CharBuffer.allocate(maxChars);
reader.read(buffer);
reader.close();
buffer.flip();
return preface + "[" + buffer.toString() + "... (" + responseBody.length + " bytes)]";
} catch (IOException ex) {
// should never happen
throw new IllegalStateException(ex);
}
}
protected void handleError(ClientHttpResponse response, HttpStatus statusCode) throws IOException {
String statusText = response.getStatusText();
HttpHeaders headers = response.getHeaders();
byte[] body = getResponseBody(response);
Charset charset = getCharset(response);
String message = getErrorMessage(statusCode.value(), statusText, body, charset);
switch (statusCode.series()) {
case CLIENT_ERROR: throw HttpClientErrorException.create(message, statusCode, statusText, headers, body, charset);
case SERVER_ERROR: throw HttpServerErrorException.create(message, statusCode, statusText, headers, body, charset);
default: throw new UnknownHttpStatusCodeException(message, statusCode.value(), statusText, headers, body, charset);
}
}
@Deprecated
protected HttpStatus getHttpStatusCode(ClientHttpResponse response) throws IOException {
HttpStatus statusCode = HttpStatus.resolve(response.getRawStatusCode());
if (statusCode == null) {
throw new UnknownHttpStatusCodeException(...);
}
return statusCode;
}
protected byte[] getResponseBody(ClientHttpResponse response) {
try {
return FileCopyUtils.copyToByteArray(response.getBody());
} catch (IOException ex) {
// ignore
}
return new byte[0];
}
@Nullable
protected Charset getCharset(ClientHttpResponse response) {
HttpHeaders headers = response.getHeaders();
MediaType contentType = headers.getContentType();
return (contentType != null ? contentType.getCharset() : null);
}
}
9.2 ExtractingResponseErrorHandler
java
public class ExtractingResponseErrorHandler extends DefaultResponseErrorHandler {
private List<HttpMessageConverter<?>> messageConverters = Collections.emptyList();
private final Map<HttpStatus, Class<? extends RestClientException>> statusMapping = new LinkedHashMap<>();
private final Map<HttpStatus.Series, Class<? extends RestClientException>> seriesMapping = new LinkedHashMap<>();
public ExtractingResponseErrorHandler() {
}
public ExtractingResponseErrorHandler(List<HttpMessageConverter<?>> messageConverters) {
this.messageConverters = messageConverters;
}
public void setMessageConverters(List<HttpMessageConverter<?>> messageConverters) {
this.messageConverters = messageConverters;
}
public void setStatusMapping(Map<HttpStatus, Class<? extends RestClientException>> statusMapping) {
if (!CollectionUtils.isEmpty(statusMapping)) {
this.statusMapping.putAll(statusMapping);
}
}
public void setSeriesMapping(Map<HttpStatus.Series, Class<? extends RestClientException>> seriesMapping) {
if (!CollectionUtils.isEmpty(seriesMapping)) {
this.seriesMapping.putAll(seriesMapping);
}
}
@Override
protected boolean hasError(HttpStatus statusCode) {
if (this.statusMapping.containsKey(statusCode)) {
return this.statusMapping.get(statusCode) != null;
} else if (this.seriesMapping.containsKey(statusCode.series())) {
return this.seriesMapping.get(statusCode.series()) != null;
} else {
return super.hasError(statusCode);
}
}
@Override
public void handleError(ClientHttpResponse response, HttpStatus statusCode) throws IOException {
if (this.statusMapping.containsKey(statusCode)) {
extract(this.statusMapping.get(statusCode), response);
} else if (this.seriesMapping.containsKey(statusCode.series())) {
extract(this.seriesMapping.get(statusCode.series()), response);
} else {
super.handleError(response, statusCode);
}
}
private void extract(@Nullable Class<? extends RestClientException> exceptionClass,
ClientHttpResponse response) throws IOException {
if (exceptionClass == null) {
return;
}
HttpMessageConverterExtractor<? extends RestClientException> extractor =
new HttpMessageConverterExtractor<>(exceptionClass, this.messageConverters);
RestClientException exception = extractor.extractData(response);
if (exception != null) {
throw exception;
}
}
}