RestTemplate对HttpClient的适配源码解读
作者:codecraft
序
本文主要研究一下RestTemplate对HttpClient的适配
ClientHttpRequestFactory
org/springframework/http/client/ClientHttpRequestFactory.java
/** * Factory for {@link ClientHttpRequest} objects. * Requests are created by the {@link #createRequest(URI, HttpMethod)} method. * * @author Arjen Poutsma * @since 3.0 */ @FunctionalInterface public interface ClientHttpRequestFactory { /** * Create a new {@link ClientHttpRequest} for the specified URI and HTTP method. * <p>The returned request can be written to, and then executed by calling * {@link ClientHttpRequest#execute()}. * @param uri the URI to create a request for * @param httpMethod the HTTP method to execute * @return the created request * @throws IOException in case of I/O errors */ ClientHttpRequest createRequest(URI uri, HttpMethod httpMethod) throws IOException; }
spring-web定义了ClientHttpRequestFactory接口,它定义了一个createRequest方法
HttpComponentsClientHttpRequestFactory
org/springframework/http/client/HttpComponentsClientHttpRequestFactory.java
public class HttpComponentsClientHttpRequestFactory implements ClientHttpRequestFactory, DisposableBean { private HttpClient httpClient; @Nullable private RequestConfig requestConfig; private boolean bufferRequestBody = true; /** * Create a new instance of the {@code HttpComponentsClientHttpRequestFactory} * with a default {@link HttpClient} based on system properties. */ public HttpComponentsClientHttpRequestFactory() { this.httpClient = HttpClients.createSystem(); } /** * Create a new instance of the {@code HttpComponentsClientHttpRequestFactory} * with the given {@link HttpClient} instance. * @param httpClient the HttpClient instance to use for this request factory */ public HttpComponentsClientHttpRequestFactory(HttpClient httpClient) { this.httpClient = httpClient; } @Override public ClientHttpRequest createRequest(URI uri, HttpMethod httpMethod) throws IOException { HttpClient client = getHttpClient(); HttpUriRequest httpRequest = createHttpUriRequest(httpMethod, uri); postProcessHttpRequest(httpRequest); HttpContext context = createHttpContext(httpMethod, uri); if (context == null) { context = HttpClientContext.create(); } // Request configuration not set in the context if (context.getAttribute(HttpClientContext.REQUEST_CONFIG) == null) { // Use request configuration given by the user, when available RequestConfig config = null; if (httpRequest instanceof Configurable) { config = ((Configurable) httpRequest).getConfig(); } if (config == null) { config = createRequestConfig(client); } if (config != null) { context.setAttribute(HttpClientContext.REQUEST_CONFIG, config); } } if (this.bufferRequestBody) { return new HttpComponentsClientHttpRequest(client, httpRequest, context); } else { return new HttpComponentsStreamingClientHttpRequest(client, httpRequest, context); } } /** * Shutdown hook that closes the underlying * {@link org.apache.http.conn.HttpClientConnectionManager ClientConnectionManager}'s * connection pool, if any. */ @Override public void destroy() throws Exception { HttpClient httpClient = getHttpClient(); if (httpClient instanceof Closeable) { ((Closeable) httpClient).close(); } } //...... }
HttpComponentsClientHttpRequestFactory实现了ClientHttpRequestFactory及DisposableBean接口;createRequest方法先拿到httpClient,然后创建createHttpUriRequest,设置RequestConfig,针对bufferRequestBody的场景HttpComponentsClientHttpRequest,否则创建HttpComponentsStreamingClientHttpRequest;destroy方法主要是关闭httpClient
ClientHttpRequest
org/springframework/http/client/ClientHttpRequest.java
public interface ClientHttpRequest extends HttpRequest, HttpOutputMessage { /** * Execute this request, resulting in a {@link ClientHttpResponse} that can be read. * @return the response result of the execution * @throws IOException in case of I/O errors */ ClientHttpResponse execute() throws IOException; }
ClientHttpRequest接口定义了execute方法,它返回ClientHttpResponse
HttpComponentsClientHttpRequest
org/springframework/http/client/HttpComponentsClientHttpRequest.java
final class HttpComponentsClientHttpRequest extends AbstractBufferingClientHttpRequest { private final HttpClient httpClient; private final HttpUriRequest httpRequest; private final HttpContext httpContext; HttpComponentsClientHttpRequest(HttpClient client, HttpUriRequest request, HttpContext context) { this.httpClient = client; this.httpRequest = request; this.httpContext = context; } @Override public String getMethodValue() { return this.httpRequest.getMethod(); } @Override public URI getURI() { return this.httpRequest.getURI(); } HttpContext getHttpContext() { return this.httpContext; } @Override protected ClientHttpResponse executeInternal(HttpHeaders headers, byte[] bufferedOutput) throws IOException { addHeaders(this.httpRequest, headers); if (this.httpRequest instanceof HttpEntityEnclosingRequest) { HttpEntityEnclosingRequest entityEnclosingRequest = (HttpEntityEnclosingRequest) this.httpRequest; HttpEntity requestEntity = new ByteArrayEntity(bufferedOutput); entityEnclosingRequest.setEntity(requestEntity); } HttpResponse httpResponse = this.httpClient.execute(this.httpRequest, this.httpContext); return new HttpComponentsClientHttpResponse(httpResponse); } /** * Add the given headers to the given HTTP request. * @param httpRequest the request to add the headers to * @param headers the headers to add */ static void addHeaders(HttpUriRequest httpRequest, HttpHeaders headers) { headers.forEach((headerName, headerValues) -> { if (HttpHeaders.COOKIE.equalsIgnoreCase(headerName)) { // RFC 6265 String headerValue = StringUtils.collectionToDelimitedString(headerValues, "; "); httpRequest.addHeader(headerName, headerValue); } else if (!HTTP.CONTENT_LEN.equalsIgnoreCase(headerName) && !HTTP.TRANSFER_ENCODING.equalsIgnoreCase(headerName)) { for (String headerValue : headerValues) { httpRequest.addHeader(headerName, headerValue); } } }); } }
HttpComponentsClientHttpRequest继承了AbstractBufferingClientHttpRequest,其executeInternal方法调用httpClient.execute,然后返回HttpComponentsClientHttpResponse
HttpComponentsStreamingClientHttpRequest
org/springframework/http/client/HttpComponentsStreamingClientHttpRequest.java
final class HttpComponentsStreamingClientHttpRequest extends AbstractClientHttpRequest implements StreamingHttpOutputMessage { private final HttpClient httpClient; private final HttpUriRequest httpRequest; private final HttpContext httpContext; @Nullable private Body body; HttpComponentsStreamingClientHttpRequest(HttpClient client, HttpUriRequest request, HttpContext context) { this.httpClient = client; this.httpRequest = request; this.httpContext = context; } @Override public String getMethodValue() { return this.httpRequest.getMethod(); } @Override public URI getURI() { return this.httpRequest.getURI(); } @Override public void setBody(Body body) { assertNotExecuted(); this.body = body; } @Override protected OutputStream getBodyInternal(HttpHeaders headers) throws IOException { throw new UnsupportedOperationException("getBody not supported"); } @Override protected ClientHttpResponse executeInternal(HttpHeaders headers) throws IOException { HttpComponentsClientHttpRequest.addHeaders(this.httpRequest, headers); if (this.httpRequest instanceof HttpEntityEnclosingRequest && this.body != null) { HttpEntityEnclosingRequest entityEnclosingRequest = (HttpEntityEnclosingRequest) this.httpRequest; HttpEntity requestEntity = new StreamingHttpEntity(getHeaders(), this.body); entityEnclosingRequest.setEntity(requestEntity); } HttpResponse httpResponse = this.httpClient.execute(this.httpRequest, this.httpContext); return new HttpComponentsClientHttpResponse(httpResponse); } //...... }
HttpComponentsStreamingClientHttpRequest继承了AbstractClientHttpRequest,实现了StreamingHttpOutputMessage接口,其getBodyInternal抛出UnsupportedOperationException,其executeInternal方法创建的是StreamingHttpEntity,然后执行httpClient.execute(this.httpRequest, this.httpContext),最后返回HttpComponentsClientHttpResponse
ClientHttpResponse
org/springframework/http/client/ClientHttpResponse.java
/** * Represents a client-side HTTP response. * Obtained via an calling of the {@link ClientHttpRequest#execute()}. * * <p>A {@code ClientHttpResponse} must be {@linkplain #close() closed}, * typically in a {@code finally} block. * * @author Arjen Poutsma * @since 3.0 */ public interface ClientHttpResponse extends HttpInputMessage, Closeable { /** * Return the HTTP status code as an {@link HttpStatus} enum value. * @return the HTTP status as an HttpStatus enum value (never {@code null}) * @throws IOException in case of I/O errors * @throws IllegalArgumentException in case of an unknown HTTP status code * @since #getRawStatusCode() * @see HttpStatus#valueOf(int) */ HttpStatus getStatusCode() throws IOException; /** * Return the HTTP status code (potentially non-standard and not * resolvable through the {@link HttpStatus} enum) as an integer. * @return the HTTP status as an integer value * @throws IOException in case of I/O errors * @since 3.1.1 * @see #getStatusCode() * @see HttpStatus#resolve(int) */ int getRawStatusCode() throws IOException; /** * Return the HTTP status text of the response. * @return the HTTP status text * @throws IOException in case of I/O errors */ String getStatusText() throws IOException; /** * Close this response, freeing any resources created. */ @Override void close(); }
ClientHttpResponse接口定义了getStatusCode、getRawStatusCode、getStatusText、close方法
HttpComponentsClientHttpResponse
org/springframework/http/client/HttpComponentsClientHttpResponse.java
final class HttpComponentsClientHttpResponse extends AbstractClientHttpResponse { private final HttpResponse httpResponse; @Nullable private HttpHeaders headers; HttpComponentsClientHttpResponse(HttpResponse httpResponse) { this.httpResponse = httpResponse; } @Override public int getRawStatusCode() throws IOException { return this.httpResponse.getStatusLine().getStatusCode(); } @Override public String getStatusText() throws IOException { return this.httpResponse.getStatusLine().getReasonPhrase(); } @Override public HttpHeaders getHeaders() { if (this.headers == null) { this.headers = new HttpHeaders(); for (Header header : this.httpResponse.getAllHeaders()) { this.headers.add(header.getName(), header.getValue()); } } return this.headers; } @Override public InputStream getBody() throws IOException { HttpEntity entity = this.httpResponse.getEntity(); return (entity != null ? entity.getContent() : StreamUtils.emptyInput()); } @Override public void close() { // Release underlying connection back to the connection manager try { try { // Attempt to keep connection alive by consuming its remaining content EntityUtils.consume(this.httpResponse.getEntity()); } finally { if (this.httpResponse instanceof Closeable) { ((Closeable) this.httpResponse).close(); } } } catch (IOException ex) { // Ignore exception on close... } } }
HttpComponentsClientHttpResponse继承了AbstractClientHttpResponse,其getBody方法返回的是httpResponse.getEntity().getContent()或者StreamUtils.emptyInput(),其close方法主要是执行EntityUtils.consume(this.httpResponse.getEntity())以及((Closeable) this.httpResponse).close()
小结
spring-web定义了ClientHttpRequestFactory接口,它定义了一个createRequest方法,HttpComponentsClientHttpRequestFactory就是RestTemplate对HttpClient的适配,其通过HttpComponentsClientHttpRequest或者HttpComponentsStreamingClientHttpRequest,将HttpClient的request适配为了spring-web的ClientHttpRequest,将response通过HttpComponentsClientHttpResponse适配为spring-web的ClientHttpResponse。
以上就是RestTemplate对HttpClient的适配的详细内容,更多关于RestTemplate HttpClient适配的资料请关注脚本之家其它相关文章!