Call 002-02-RestTemplate- initialization process

A brief

  RestTemplate default constructor call, RestTemplate object creation request by using the HTTP implemented in java.net package at the bottom, an HTTP request can specify a different manner by using ClientHttpRequestFactory.

  Using spring5.0.1

  Default SimpleClientHttpRequestFactory, it is ClientHttpRequestFactory implementation class. The following process:

1) using a new instance of the default constructor

  Rest Rest Template Template template = new ();

2) internal RestTemplate by calling doExecute method, first of all it is to get ClientHttpRequest

doExcute core processing

// produced by a plant ClientHttpRequestFactory ClientHttpRequest 
ClientHttpRequest Request = the this .createRequest (URL, Method);
 IF (! The requestCallback = null ) {
     // encapsulates the request header and request body, using HttpMessageConverter types 
    requestCallback.doWithRequest (Request); 
} 
/ / ClientHttpRequest & execution request execute 
Response = request.execute ();
 // Response error processing 
the this .handleResponse (URL, Method, Response);
 IF (responseExtractor == null ) { 
    Resource = null ;
     return Resource; 
}

var14 = responseExtractor.extractData(response);

Source

    @Nullable
    protected <T> T doExecute(URI url, @Nullable HttpMethod method, @Nullable RequestCallback requestCallback, @Nullable ResponseExtractor<T> responseExtractor) throws RestClientException {
        Assert.notNull(url, "'url' must not be null");
        Assert.notNull(method, "'method' must not be null");
        ClientHttpResponse response = null;

        Object var14;
        try {
            String resource;
            try {
                ClientHttpRequest request = this.createRequest(url, method);
                if(requestCallback != null) {
                    requestCallback.doWithRequest(request);
                }

                response = request.execute();
                this.handleResponse(url, method, response);
                if(responseExtractor == null) {
                    resource = null;
                    return resource;
                }

                var14 = responseExtractor.extractData(response);
            } catch (IOException var12) {
                resource = url.toString();
                String query = url.getRawQuery();
                resource = query != null?resource.substring(0, resource.indexOf(63)):resource;
                throw new ResourceAccessException("I/O error on " + method.name() + " request for \"" + resource + "\": " + var12.getMessage(), var12);
            }
        } finally {
            if(response != null) {
                response.close();
            }

        }

        return var14;
    }
View Code

  

  Here method calls ClientHttpRequest createRequest methods in HttpAccessor the third step.

3) RestTemplate implements the abstract class HttpAccessor, so you can call the parent class createRequest

In the HttpAccessor

   private ClientHttpRequestFactory requestFactory = new SimpleClientHttpRequestFactory();
    public ClientHttpRequestFactory getRequestFactory() {
        return this.requestFactory;
    }

  There is also provided a method of plant ClientHttpRequestFactory custom request, to the subsequent use

    public void setRequestFactory(ClientHttpRequestFactory requestFactory) {
        Assert.notNull(requestFactory, "ClientHttpRequestFactory must not be null");
        this.requestFactory = requestFactory;
    }
    protected ClientHttpRequest createRequest(URI url, HttpMethod method) throws IOException {
        ClientHttpRequest request = this.getRequestFactory().createRequest(url, method);
        if(this.logger.isDebugEnabled()) {
            this.logger.debug("Created " + method.name() + " request for \"" + url + "\"");
        }

        return request;
    }

4) SimpleClientHttpRequestFactory achieved ClientHttpRequest, while achieving the method

  Note bufferRequestBody is set in RestTemplate, it is a sign of whether to use a cached stream, the default is true, the disadvantage is that when sending large amounts of data, such as put / post preservation and modified, the memory consumption may be serious. So this time can be set RestTemplate.setBufferRequestBody (false);

  That is implemented using SimpleStreamingClientHttpRequest.

    public ClientHttpRequest createRequest(URI uri, HttpMethod httpMethod) throws IOException {
        HttpURLConnection connection = this.openConnection(uri.toURL(), this.proxy);
        this.prepareConnection(connection, httpMethod.name());
        return (ClientHttpRequest)(this.bufferRequestBody?new SimpleBufferingClientHttpRequest(connection, this.outputStreaming):new SimpleStreamingClientHttpRequest(connection, this.chunkSize, this.outputStreaming));
    }

  The first line: Creating java.net.HttpURLConnection 

  Second row: create connection properties, and set up setDoInput

5) openConnection opens the connection, but is connected prepareConnection various preparations for the requestor

    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(false);
        } else {
            connection.setDoOutput(true);
        }

        connection.setRequestMethod(httpMethod);
    }

5.1, set connection time: connectTimeout

5.2, set read timeout: readTimeout

5.3, set the URL to allow input: connection.setDoInput (true); // default true

  URL connection can be used for input and / or output. If you plan to use the URL connection for input, then set DoInput flag is set to true; otherwise, set to false. The default value is true.

  httpUrlConnection.setDoInput (true); later be used conn.getInputStream () read ().;

5.4、setDoOutput

  URL connection can be used for input and / or output. If you intend to use the URL connection for output, set DoOutput flag is set to true, if it is not, and false default value is false.

  If the request is get

    get request less than conn.getOutputStream (), since additional parameters directly after the address, the default is false. 

  If a post, put, patch, delete

    Several more requests will setDoOutput set to true.

    Equivalent can be used: httpUrlConnection.setDoOutput (true); later be used conn.getOutputStream () write ().

6、执行requestCallback.doWithRequest(request);

  RequestCallback request body and encapsulates the request header object, that is to say in which the object can get request parameters we need.

  When performing doWithRequest, there is a very important step in front of him and Connection send the request body are closely related, we know that SimpleBufferingClientHttpRequest.addHeaders method request header, the request body bufferedOutput is how to assign it? In doWithRequest which is as follows StringHttpMessageConverter (other MessageConvert, too, there is often the cause garbled)

  The above 8.1, it is found RequestCallback head and body for operating the request, request before execution. Here are two of the implementation class RequestCallback

AcceptHeaderRequestCallback Only processing request header, for getXXX () methods.
HttpEntityRequestCallback AcceptHeaderRequestCallback request can be processed in succession and the head body, for putXXX (), postXXX () and exchange () method.

  Which HttpEntityRequestCallback inheritance: HttpEntityRequestCallback extends RestTemplate.AcceptHeaderRequestCallback

  Therefore first check under AcceptHeaderRequestCallback Code

        public void doWithRequest(ClientHttpRequest request) throws IOException {
            if(this.responseType != null) {
                Class<?> responseClass = null;
                if(this.responseType instanceof Class) {
                    responseClass = (Class)this.responseType;
                }

                List<MediaType> allSupportedMediaTypes = new ArrayList();
                Iterator var4 = RestTemplate.this.getMessageConverters().iterator();//第一步

                while(var4.hasNext()) {
                    HttpMessageConverter<?> converter = (HttpMessageConverter)var4.next();
                    if(responseClass != null) {
                        if(converter.canRead(responseClass, (MediaType)null)) {
                            allSupportedMediaTypes.addAll(this.getSupportedMediaTypes(converter));
                        }
                    } else if(converter instanceof GenericHttpMessageConverter) {
                        GenericHttpMessageConverter<?> genericConverter = (GenericHttpMessageConverter)converter;
                        if(genericConverter.canRead(this.responseType, (Class)null, (MediaType)null)) {
                            allSupportedMediaTypes.addAll(this.getSupportedMediaTypes(converter));
                        }
                    }
                }

                if(!allSupportedMediaTypes.isEmpty()) {
                    MediaType.sortBySpecificity(allSupportedMediaTypes);
                    if(RestTemplate.this.logger.isDebugEnabled()) {
                        RestTemplate.this.logger.debug("Setting request Accept header to " + allSupportedMediaTypes);
                    }
                    request.getHeaders().setAccept(allSupportedMediaTypes);
                }
            }

        }

  Notes The first step: Get RestTemplate all MessageConverters binding.

    There are above   bound when RestTemplate five basic initialization, and much more, initialization code

    public RestTemplate() {
        this.messageConverters = new ArrayList();
        this.errorHandler = new DefaultResponseErrorHandler();
        this.uriTemplateHandler = new DefaultUriBuilderFactory();
        this.headersExtractor = new RestTemplate.HeadersExtractor();
        this.messageConverters.add(new ByteArrayHttpMessageConverter());
        this.messageConverters.add(new StringHttpMessageConverter());
        this.messageConverters.add(new ResourceHttpMessageConverter(false));
        this.messageConverters.add(new SourceHttpMessageConverter());
        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());
        }

    }
View Code

  At this point you can analyze the code StringHttpMessageConverter    

    protected void writeInternal(String str, HttpOutputMessage outputMessage) throws IOException {
        if(this.writeAcceptCharset) {
            outputMessage.getHeaders().setAcceptCharset(this.getAcceptedCharsets());
        }

        Charset charset = this.getContentTypeCharset(outputMessage.getHeaders().getContentType());
        StreamUtils.copy(str, charset, outputMessage.getBody());
    }

  Str which is the body of the request; HttpOutputMessage ClientHttpRequest object is the object of our preparation, which is above SimpleBufferingClientHttpRequest extends AbstractBufferingClientHttpRequest

  Thus, the first call the parent class of the flow, the contents written to the stream, and then call the parent class in executeInternal method calls itself executeInternal this method, as the next step

  Note Point 1: charset character set, may be from client;

    public static final Charset DEFAULT_CHARSET; // static block of code, i.e. set ISO_8859_1, but network traffic is typically UTF-8, where it is most needed to set the encoding

    static {
        DEFAULT_CHARSET = StandardCharsets.ISO_8859_1;
    }

  Note point 2: StreamUtils spring is a class for processing stream, and is the outputStream inputStream java.io package, not java8 in Steam. It depends only on the use of spring-core

    The copy method takes three parameters: the copied string, write the file specified character set specified destination (outputStream).

    See more: https: //blog.csdn.net/neweastsun/article/details/79432763

7) is then performed response = request.execute ();

Call Interface ClientHttpRequest 

public interface ClientHttpRequest extends HttpRequest, HttpOutputMessage {
    ClientHttpResponse execute() throws IOException;
}

Example SimpleBufferingClientHttpRequest then request the package body and the request header

View executeInternal

    protected ClientHttpResponse executeInternal(HttpHeaders headers, byte[] bufferedOutput) throws IOException {
        addHeaders(this.connection, headers);
        if(HttpMethod.DELETE == this.getMethod() && bufferedOutput.length == 0) {
            this.connection.setDoOutput(false);
        }

        if(this.connection.getDoOutput() && this.outputStreaming) {
            this.connection.setFixedLengthStreamingMode(bufferedOutput.length);
        }

        this.connection.connect();
        if(this.connection.getDoOutput()) {
            FileCopyUtils.copy(bufferedOutput, this.connection.getOutputStream());
        } else {
            this.connection.getResponseCode();
        }

        return new SimpleClientHttpResponse(this.connection);
    }

When the delete request through the request body and whether there are objects to determine whether to send the request body

If a delete request, the first set DoOutput = true, then the volume data according to whether there is a request, then the request package body

FileCopyUtils.copy(bufferedOutput, this.connection.getOutputStream());

8) analytical response

Followed by parsing the response, mainly to resolve the Error.

  this.handleResponse(url, method, response);

Internal processing error processing mostly resolved

    protected void handleResponse(URI url, HttpMethod method, ClientHttpResponse response) throws IOException {
        ResponseErrorHandler errorHandler = this.getErrorHandler();
        boolean hasError = errorHandler.hasError(response);
        if(this.logger.isDebugEnabled()) {
            try {
                this.logger.debug(method.name() + " request for \"" + url + "\" resulted in " + response.getRawStatusCode() + " (" + response.getStatusText() + ")" + (hasError?"; invoking error handler":""));
            } catch (IOException var7) {
                ;
            }
        }

        if(hasError) {
            errorHandler.handleError(url, method, response);
        }

    }
View Code

See Address:

https://my.oschina.net/heweipo/blog/801653

 

Guess you like

Origin www.cnblogs.com/bjlhx/p/8652763.html