Spring RestTemplate 源码解析

作者: David_jim | 来源:发表于2018-11-10 15:47 被阅读6次
    • RestTemplate的概述
      spring 架构中,RestTemplate是客户端http请求的核心类,它使和服务端的请求更加简单,同时强化了RestFul的原理,它会处理http请求的连接,使应用代码只需提供url和参数,解析结果就可以了。
      RestTemplate默认是依赖于标准sdk 工具去建立连接,你可以通过setRequestFactory方法用其它的http库来替换,比如apach httpComponents,Netty 和OkHttp
    • RestTemplate的类图


      RestTemplate类图
    1. HttpAccessor 类
      RestTemplate的基类,是一个抽象类,提供了一些公共的属性,如 ClientHttpRequestFactory,ClientHttpRequestFactory 是clientHttpRequest的工厂类,通过 createRequest 来创建http请求的方法
    2. InterceptingHttpAccessor 类
      这个是 HttpAccessor的一个抽象子类,多增加了 请求拦截器相关的属性,ClientHttpRequestInterceptor,而这个ClientHttpRequestInterceptor是 spring cloud中各种服务治理的关键,如客户端负载均衡,链路跟踪等
    • RestTemplate的doExecute 方法

    该方法是RestTemplate的核心方法

    image.png

    它主要有四个参数

    1. url 请求的http 地址
    2. method http请求的method
    3. requestCallback 是一个接口Request Callback
    4. responseExtractor 也是一个接口 ResponseExtractor
      我们来设想下,如果我们自己设计一个封装http请求的组件,一定也会遵守开闭原则,开放出可以让用户自定义的接口,那第三,第四个参数就是这个作用的。
      来看下,spring 里默认是怎么做的,首先看下这两个接口的定义
    public interface RequestCallback {
    
        /**
         * Gets called by {@link RestTemplate#execute} with an opened {@code ClientHttpRequest}.
         * Does not need to care about closing the request or about handling errors:
         * this will all be handled by the {@code RestTemplate}.
         * @param request the active HTTP request
         * @throws IOException in case of I/O errors
         */
        void doWithRequest(ClientHttpRequest request) throws IOException;
    
    }
    
    public interface ResponseExtractor<T> {
    
        /**
         * Extract data from the given {@code ClientHttpResponse} and return it.
         * @param response the HTTP response
         * @return the extracted data
         * @throws IOException in case of I/O errors
         */
        T extractData(ClientHttpResponse response) throws IOException;
    
    }
    

    很明显,这两个接口分别是在请求前,ClientHttpRequest请求前会作回调,而在请求结束后,又会调用ResponseExtractor去作请求结果解析的动作
    再来看下方法createRequest

    protected ClientHttpRequest createRequest(URI url, HttpMethod method) throws IOException {
            ClientHttpRequest request = getRequestFactory().createRequest(url, method);
            if (logger.isDebugEnabled()) {
                logger.debug("Created " + method.name() + " request for \"" + url + "\"");
            }
            return request;
        }
    

    getRequestFactory()InterceptingHttpAccessor 中被重载了

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

    如果有设置拦截器,则返回的是一个InterceptingClientHttpRequestFactory类,而这个类创建的是

    @Override
        protected ClientHttpRequest createRequest(URI uri, HttpMethod httpMethod, ClientHttpRequestFactory requestFactory) {
            return new InterceptingClientHttpRequest(requestFactory, this.interceptors, uri, httpMethod);
        }
    

    Resttemplate 调用 的ClientHttpRequest.execute() 方法,其实就是InterceptingClientHttpRequest的方法,再来看下这个类的实现吧

    @Override
        protected final ClientHttpResponse executeInternal(HttpHeaders headers, byte[] bufferedOutput) throws IOException {
            InterceptingRequestExecution requestExecution = new InterceptingRequestExecution();
            return requestExecution.execute(this, bufferedOutput);
        }
    

    最终是通过InterceptingRequestExecution类来完成最终的调用

    @Override
            public ClientHttpResponse execute(HttpRequest request, final byte[] body) throws IOException {
                if (this.iterator.hasNext()) {
                    ClientHttpRequestInterceptor nextInterceptor = this.iterator.next();
                    return nextInterceptor.intercept(request, body, this);
                }
                else {
                    ClientHttpRequest delegate = requestFactory.createRequest(request.getURI(), request.getMethod());
                    for (Map.Entry<String, List<String>> entry : request.getHeaders().entrySet()) {
                        List<String> values = entry.getValue();
                        for (String value : values) {
                            delegate.getHeaders().add(entry.getKey(), value);
                        }
                    }
                    if (body.length > 0) {
                        if (delegate instanceof StreamingHttpOutputMessage) {
                            StreamingHttpOutputMessage streamingOutputMessage = (StreamingHttpOutputMessage) delegate;
                            streamingOutputMessage.setBody(new StreamingHttpOutputMessage.Body() {
                                @Override
                                public void writeTo(final OutputStream outputStream) throws IOException {
                                    StreamUtils.copy(body, outputStream);
                                }
                            });
                        }
                        else {
                            StreamUtils.copy(body, delegate.getBody());
                        }
                    }
                    return delegate.execute();
                }
            }
    

    从上面的代码可以很清晰的看到是怎么调用ClientHttpRequestInterceptor

    相关文章

      网友评论

        本文标题:Spring RestTemplate 源码解析

        本文链接:https://www.haomeiwen.com/subject/dgmzxqtx.html