RestTemplate原理分析

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 用于处理服务端响应错误,提供实现类DefaultResponseErrorHandlerExtractingResponseErrorHandler

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;
		}
	}
}
相关推荐
Code季风8 小时前
深入理解微服务中的服务注册与发现(Consul)
java·运维·微服务·zookeeper·架构·go·consul
光军oi8 小时前
java微服务(Springboot篇)——————IDEA搭建第一个Springboot入门项目
java·spring boot·微服务
guojl9 小时前
RestTemplate使用手册
spring cloud·微服务
Ken_111510 小时前
SpringCloud系列(51)--SpringCloud Stream之使用分组解决消息重复消费问题
spring cloud
LCG元10 小时前
云原生微服务间的异步消息通信:最终一致性与系统容错的架构实战
微服务·云原生·架构
lwb_011811 小时前
SpringCloud——Gateway新一代网关
spring·spring cloud·gateway
vim怎么退出13 小时前
万字长文带你了解微前端架构
前端·微服务·前端框架
述雾学java14 小时前
Spring Cloud Feign 整合 Sentinel 实现服务降级与熔断保护
java·spring cloud·sentinel
何苏三月17 小时前
SpringCloud系列 - Sentinel 服务保护(四)
spring·spring cloud·sentinel