RestTemplate源码分析

背景:之前restTemplate调用,json序列化的时候,出了问题,然后临时匆忙没有研究restTemplate的源码,回过头来,想看看。

debug走起。

 public static void main(String[] args) {
        RestTemplate restTemplate1 = new RestTemplate();
        String url = "http://***";
        CheckAccountSaveRpcParam checkAccountSaveRpcParam = new CheckAccountSaveRpcParam(StringUtils.genId(),
                1, LocalDateTime.now(), 1);
        ResponseEntity responseEntity =
                restTemplate1.postForEntity(url, checkAccountSaveRpcParam, String.class);
        String responseBody = responseEntity.getBody();
        Result obj = JSON.parseObject(responseBody, Result.class);
        Assert.isTrue(obj.getCode() == 0, null);
    }

看RestTemplate的构造函数。可以看到,RestTemplate维护了一个List的变量messageConverters,再构造方法中,往这个list中添加了各种MessageConverter,总共有八个。

private final List> messageConverters = new ArrayList>();

// 如果引入这个jackson包,有这两个类,则在构造方法中,就会把添加jackson的httpmessageConverter   
private static final boolean jackson2Present = ClassUtils.isPresent("com.fasterxml.jackson.databind.ObjectMapper", RestTemplate.class.getClassLoader()) && ClassUtils.isPresent("com.fasterxml.jackson.core.JsonGenerator", RestTemplate.class.getClassLoader());
// gson同理
private static final boolean gsonPresent =
            ClassUtils.isPresent("com.google.gson.Gson", RestTemplate.class.getClassLoader());
public RestTemplate() {
        this.messageConverters.add(new ByteArrayHttpMessageConverter());
        this.messageConverters.add(new StringHttpMessageConverter());
        this.messageConverters.add(new ResourceHttpMessageConverter());
        this.messageConverters.add(new SourceHttpMessageConverter());
// 这个转换器里面其实包含了很多转换器,其中就包括MappingJackson2HttpMessageConverter转换器,但是因为它没有继承GenericHttpMessageConverter,不是通用转换器,所以不会对post的json进行转换,这个应该是对form类型的数据进行转换用的。
        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());
        }
    }

发起post请求

@Override
    public  ResponseEntity postForEntity(String url, Object request, Class responseType, Object... uriVariables)
            throws RestClientException {
// 构造一个request回调,requestCallback包含了请求数据和响应类型,
// 请求数据用HttpEntity包裹,HttpEntity又包含了header和body。
        RequestCallback requestCallback = httpEntityCallback(request, responseType);
// 构造了一个响应提取器,响应提取器包含了响应类型,以及把restTemplate
// 里的messageConvert引用过来了,所以自然可想到,请求响应最后会使用这个类来进行转换提取数据
        ResponseExtractor> responseExtractor = responseEntityExtractor(responseType);
        return execute(url, HttpMethod.POST, requestCallback, responseExtractor, uriVariables);
    }

private HttpEntityRequestCallback(Object requestBody, 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;
            }
        }
public ResponseEntityResponseExtractor(Type responseType) {
            if (responseType != null && Void.class != responseType) {
                this.delegate = new HttpMessageConverterExtractor(responseType, getMessageConverters(), logger);
            }
            else {
                this.delegate = null;
            }
        }

@SuppressWarnings("unchecked")
    HttpMessageConverterExtractor(Type responseType, List> messageConverters, Log logger) {
        Assert.notNull(responseType, "'responseType' must not be null");
        Assert.notEmpty(messageConverters, "'messageConverters' must not be empty");
        this.responseType = responseType;
        this.responseClass = (responseType instanceof Class) ? (Class) responseType : null;
        this.messageConverters = messageConverters;
        this.logger = logger;
    }
 
 

构造了请求回调包装、响应提取器之后,继续发起请求

@Override
    public  T execute(String url, HttpMethod method, RequestCallback requestCallback,
            ResponseExtractor responseExtractor, Object... uriVariables) throws RestClientException {
// 这里获取到默认的url模板处理器,然后扩展(其实就是替换)url变量,也就是说,              
// 之前restTemplate1.postForEntity(url, checkAccountSaveRpcParam, String.class)发送请求的时候,
//方法可变参数里再添加参数之后,会在这里将url的变量替换。

        URI expanded = getUriTemplateHandler().expand(url, uriVariables);
        return doExecute(expanded, method, requestCallback, responseExtractor);
    }

@Override
    public URI expand(String uriTemplate, Object... uriVariables) {
        URI url = expandInternal(uriTemplate, uriVariables);
        return insertBaseUrl(url);
    }

@Override
    protected URI expandInternal(String uriTemplate, Object... uriVariables) {
    // 打碎拆分url  
            UriComponentsBuilder uriComponentsBuilder = initUriComponentsBuilder(uriTemplate);
        // 从方法名可以看出,这是扩充变量以及编码
            UriComponents uriComponents = expandAndEncode(uriComponentsBuilder, uriVariables);
        return createUri(uriComponents);
    }


    /** 从这个javadoc注释里,可以看到,这个方法就是把url打碎拆分成一个个部分,比如scheme、host、port、path等,然后维护在UriComponentsBuilder成员变量中
     * Create a {@code UriComponentsBuilder} from the URI template string.
     * This implementation also breaks up the path into path segments depending
     * on whether {@link #setParsePath parsePath} is enabled.
     */
    protected UriComponentsBuilder initUriComponentsBuilder(String uriTemplate) {
        UriComponentsBuilder builder = UriComponentsBuilder.fromUriString(uriTemplate);
        if (shouldParsePath() && !isStrictEncoding()) {
            List pathSegments = builder.build().getPathSegments();
            builder.replacePath(null);
            for (String pathSegment : pathSegments) {
                builder.pathSegment(pathSegment);
            }
        }
        return builder;
    }

public static UriComponentsBuilder fromUriString(String uri) {
        Assert.notNull(uri, "URI must not be null");
        Matcher matcher = URI_PATTERN.matcher(uri);
        if (matcher.matches()) {
            UriComponentsBuilder builder = new UriComponentsBuilder();
            String scheme = matcher.group(2);
            String userInfo = matcher.group(5);
            String host = matcher.group(6);
            String port = matcher.group(8);
            String path = matcher.group(9);
            String query = matcher.group(11);
            String fragment = matcher.group(13);
            boolean opaque = false;
            if (StringUtils.hasLength(scheme)) {
                String rest = uri.substring(scheme.length());
                if (!rest.startsWith(":/")) {
                    opaque = true;
                }
            }
            builder.scheme(scheme);
            if (opaque) {
                String ssp = uri.substring(scheme.length()).substring(1);
                if (StringUtils.hasLength(fragment)) {
                    ssp = ssp.substring(0, ssp.length() - (fragment.length() + 1));
                }
                builder.schemeSpecificPart(ssp);
            }
            else {
                builder.userInfo(userInfo);
                builder.host(host);
                if (StringUtils.hasLength(port)) {
                    builder.port(port);
                }
                builder.path(path);
                builder.query(query);
            }
            if (StringUtils.hasText(fragment)) {
                builder.fragment(fragment);
            }
            return builder;
        }
        else {
            throw new IllegalArgumentException("[" + uri + "] is not a valid URI");
        }
    }

扩充替换变量以及编码

protected UriComponents expandAndEncode(UriComponentsBuilder builder, Object[] uriVariables) {
        if (!isStrictEncoding()) {
// 进入这里,获取到的是HierarchicalUriComponents变量
            return builder.buildAndExpand(uriVariables).encode();
        }
        else {
            Object[] encodedUriVars = new Object[uriVariables.length];
            for (int i = 0; i < uriVariables.length; i++) {
                encodedUriVars[i] = applyStrictEncoding(uriVariables[i]);
            }
            return builder.buildAndExpand(encodedUriVars);
        }
    }
public final UriComponents expand(Object... uriVariableValues) {
        Assert.notNull(uriVariableValues, "'uriVariableValues' must not be null");
// VarArgsTemplateVariables也就是维护了一个list的迭代器
        return expandInternal(new VarArgsTemplateVariables(uriVariableValues));
    }

HierarchicalUriComponents分层uri组件一层一层拆分、替换url变量。

protected HierarchicalUriComponents expandInternal(UriTemplateVariables uriVariables) {
        Assert.state(!this.encoded, "Cannot expand an already encoded UriComponents object");

        String schemeTo = expandUriComponent(getScheme(), uriVariables);
        String userInfoTo = expandUriComponent(this.userInfo, uriVariables);
        String hostTo = expandUriComponent(this.host, uriVariables);
        String portTo = expandUriComponent(this.port, uriVariables);
        PathComponent pathTo = this.path.expand(uriVariables);
        MultiValueMap paramsTo = expandQueryParams(uriVariables);
        String fragmentTo = expandUriComponent(getFragment(), uriVariables);

        return new HierarchicalUriComponents(schemeTo, userInfoTo, hostTo, portTo,
                pathTo, paramsTo, fragmentTo, false, false);
    }
// 看着扩展url方法,可以看到就是正则匹配,然后匹配到就替换掉变量。
static String expandUriComponent(String source, UriTemplateVariables uriVariables) {
        if (source == null) {
            return null;
        }
        if (source.indexOf('{') == -1) {
            return source;
        }
        if (source.indexOf(':') != -1) {
            source = sanitizeSource(source);
        }
        Matcher matcher = NAMES_PATTERN.matcher(source);
        StringBuffer sb = new StringBuffer();
        while (matcher.find()) {
            String match = matcher.group(1);
            String variableName = getVariableName(match);
            Object variableValue = uriVariables.getValue(variableName);
            if (UriTemplateVariables.SKIP_VALUE.equals(variableValue)) {
                continue;
            }
            String variableValueString = getVariableValueAsString(variableValue);
            String replacement = Matcher.quoteReplacement(variableValueString);
            matcher.appendReplacement(sb, replacement);
        }
        matcher.appendTail(sb);
        return sb.toString();
    }

替换了变量和编码之后,可以看到就是创建普通的URI对象。

private URI createUri(UriComponents uriComponents) {
        try {
            // Avoid further encoding (in the case of strictEncoding=true)
            return new URI(uriComponents.toUriString());
        }
        catch (URISyntaxException ex) {
            throw new IllegalStateException("Could not create URI object: " + ex.getMessage(), ex);
        }
    }

这里还会把base url添加到url前面,如果设置了的话。

@Override
    public URI expand(String uriTemplate, Object... uriVariables) {
        URI url = expandInternal(uriTemplate, uriVariables);
        return insertBaseUrl(url);
    }

url构造好了之后,就是发起请求了。

protected  T doExecute(URI url, HttpMethod method, RequestCallback requestCallback,
            ResponseExtractor responseExtractor) throws RestClientException {

        Assert.notNull(url, "'url' must not be null");
        Assert.notNull(method, "'method' must not be null");
        ClientHttpResponse response = null;
        try {
            ClientHttpRequest request = createRequest(url, method);
            if (requestCallback != null) {
                requestCallback.doWithRequest(request);
            }
            response = request.execute();
            handleResponse(url, method, response);
            if (responseExtractor != null) {
                return responseExtractor.extractData(response);
            }
            else {
                return null;
            }
        }
        catch (IOException ex) {
            String resource = url.toString();
            String query = url.getRawQuery();
            resource = (query != null ? resource.substring(0, resource.indexOf(query) - 1) : resource);
            throw new ResourceAccessException("I/O error on " + method.name() +
                    " request for \"" + resource + "\": " + ex.getMessage(), ex);
        }
        finally {
            if (response != null) {
                response.close();
            }
        }
    }
protected ClientHttpRequest createRequest(URI url, HttpMethod method) throws IOException {
// 通过获取requestFactory工厂获取Request,如果,要设置http超时时间等参数,就可以通过改变这个requestFactory来达到效果
        ClientHttpRequest request = getRequestFactory().createRequest(url, method);
        if (logger.isDebugEnabled()) {
            logger.debug("Created " + method.name() + " request for \"" + url + "\"");
        }
        return request;
    }

@Override
    public ClientHttpRequestFactory getRequestFactory() {
        ClientHttpRequestFactory delegate = super.getRequestFactory();
        if (!CollectionUtils.isEmpty(getInterceptors())) {
            return new InterceptingClientHttpRequestFactory(delegate, getInterceptors());
        }
        else {
            return delegate;
        }
    }

默认的HttpRequestFactory是simpleClientHttpRequest,可以看到这个工厂里面维护了超时时间等参数。

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;
@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);
        }
        else {
            return new SimpleStreamingClientHttpRequest(connection, this.chunkSize, this.outputStreaming);
        }
    }
protected  T doExecute(URI url, HttpMethod method, RequestCallback requestCallback,
            ResponseExtractor responseExtractor) throws RestClientException {

        Assert.notNull(url, "'url' must not be null");
        Assert.notNull(method, "'method' must not be null");
        ClientHttpResponse response = null;
        try {
            ClientHttpRequest request = createRequest(url, method);
            if (requestCallback != null) {
    // 创建httpReques之后,这里使用requestCallback对body进行转换。
                requestCallback.doWithRequest(request);
            }
            response = request.execute();
            handleResponse(url, method, response);
            if (responseExtractor != null) {
                return responseExtractor.extractData(response);
            }
            else {
                return null;
            }
        }
        catch (IOException ex) {
            String resource = url.toString();
            String query = url.getRawQuery();
            resource = (query != null ? resource.substring(0, resource.indexOf(query) - 1) : resource);
            throw new ResourceAccessException("I/O error on " + method.name() +
                    " request for \"" + resource + "\": " + ex.getMessage(), ex);
        }
        finally {
            if (response != null) {
                response.close();
            }
        }
    }
public void doWithRequest(ClientHttpRequest httpRequest) throws IOException {
// 调用父类也就是
            super.doWithRequest(httpRequest);
        }

public void doWithRequest(ClientHttpRequest httpRequest) throws IOException {
            super.doWithRequest(httpRequest);
                        // requestEntity没有body
            if (!this.requestEntity.hasBody()) {
                。。。
            }
            else {
                Object requestBody = this.requestEntity.getBody();
                Class requestBodyClass = requestBody.getClass();
                Type requestBodyType = (this.requestEntity instanceof RequestEntity ?
                        ((RequestEntity)this.requestEntity).getType() : requestBodyClass);
                HttpHeaders requestHeaders = this.requestEntity.getHeaders();
                MediaType requestContentType = requestHeaders.getContentType();
// 这里可以看到,遍历转换器,查看是否可以转换
                for (HttpMessageConverter messageConverter : getMessageConverters()) {
// 这个转换器是否实现了GenericHttpMessageConverter这个通用转换器接口,
                    if (messageConverter instanceof GenericHttpMessageConverter) {
                        GenericHttpMessageConverter genericMessageConverter = (GenericHttpMessageConverter) messageConverter;
                        if (genericMessageConverter.canWrite(requestBodyType, requestBodyClass, requestContentType)) {
                            if (!requestHeaders.isEmpty()) {
                                httpRequest.getHeaders().putAll(requestHeaders);
                            }
                            if (logger.isDebugEnabled()) {
                                if (requestContentType != null) {
                                    logger.debug("Writing [" + requestBody + "] as \"" + requestContentType +
                                            "\" using [" + messageConverter + "]");
                                }
                                else {
                                    logger.debug("Writing [" + requestBody + "] using [" + messageConverter + "]");
                                }

                            }
                            genericMessageConverter.write(
                                    requestBody, requestBodyType, requestContentType, httpRequest);
                            return;
                        }
                    }
// 不是通用转换器进入这里
                    else if (messageConverter.canWrite(requestBodyClass, requestContentType)) {
                        if (!requestHeaders.isEmpty()) {
                            httpRequest.getHeaders().putAll(requestHeaders);
                        }
                        if (logger.isDebugEnabled()) {
                            if (requestContentType != null) {
                                logger.debug("Writing [" + requestBody + "] as \"" + requestContentType +
                                        "\" using [" + messageConverter + "]");
                            }
                            else {
                                logger.debug("Writing [" + requestBody + "] using [" + messageConverter + "]");
                            }

                        }
                        ((HttpMessageConverter) messageConverter).write(
                                requestBody, requestContentType, httpRequest);
                        return;
                    }
                }
                String message = "Could not write request: no suitable HttpMessageConverter found for request type [" +
                        requestBodyClass.getName() + "]";
                if (requestContentType != null) {
                    message += " and content type [" + requestContentType + "]";
                }
                throw new RestClientException(message);
            }
        }
    }
 
 

摘取一个StringHttpMessageConverter看一下

@Override
    public boolean canRead(Class clazz, MediaType mediaType) {
        return supports(clazz) && canRead(mediaType);
    }
@Override
    public boolean supports(Class clazz) {
        return String.class == clazz;
    }

protected boolean canRead(MediaType mediaType) {
        if (mediaType == null) {
            return true;
        }
        for (MediaType supportedMediaType : getSupportedMediaTypes()) {
            if (supportedMediaType.includes(mediaType)) {
                return true;
            }
        }
        return false;
    }

解析各种转换器支持的类型,然后防止到request的header。

            request.getHeaders().setAccept(allSupportedMediaTypes);

你可能感兴趣的:(RestTemplate源码分析)