美文网首页spring
SpringCloud解析一:RestTemplate源码分析

SpringCloud解析一:RestTemplate源码分析

作者: 一根线条 | 来源:发表于2019-12-19 00:02 被阅读0次

    在我们使用Spring框架进行应用开发的时候,RestTemplate组件的使用越来越频繁,在这里我简单的梳理下它的源码,从而更深入的理解其工作原理,同时也为后面的Ribbon的使用打下基础。

    首先我们从一张较为简洁的类图开始,从全局了解其继承关系

    RestTemplate继承关系

    1,HttpAccessor抽象类

    在该抽象类中重点关注setRequestFactory、getRequestFactory与createRequest三个方法。顾名思义,setRequestFactory与getRequestFactory分别就是为了设置属性requestFactory的值以及返回该值,createRequest方法是根据请求的URI地址以及请求的HTTP方法得到一个ClientHttpRequest类型的对象。

    默认其requestFactory属性为ClientHttpRequestFactory类型的SimpleClientHttpRequestFactory实例对象。该实例的内部将使用JDK自带的HttpURLConnection来建立http连接,如下所示

    @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);
      }
    }
    

    重点:RequestFactory必须是ClientHttpRequestFactory类型的。 除了这里默认的SimpleClientHttpRequestFactory,常用的还有InterceptingClientHttpRequestFactory。

    2,InterceptingHttpAccessor抽象类

    该类重写了HttpAccessor中的getRequestFactory方法,如果其中的拦截器(interceptors)为空,则直接调用父类的getRequestFactory方法直接返回,否则实例化InterceptingClientHttpRequestFactory工厂对象并返回,如下代码所示

    @Override
    public ClientHttpRequestFactory getRequestFactory() {
      List<ClientHttpRequestInterceptor> interceptors = getInterceptors();
      if (!CollectionUtils.isEmpty(interceptors)) {
        ClientHttpRequestFactory factory = this.interceptingRequestFactory;
        if (factory == null) {
          factory = new InterceptingClientHttpRequestFactory(super.getRequestFactory(), interceptors);
          this.interceptingRequestFactory = factory;
        }
        return factory;
       } else {
        return super.getRequestFactory();
      }
    }
    

    其InterceptingClientHttpRequestFactory的createRequest方法将返回一个ClientHttpRequest类型的InterceptingClientHttpRequest实例对象

    而默认的SimpleClientHttpRequestFactory返回的是ClientHttpRequest类型的SimpleBufferingClientHttpRequest或者SimpleStreamingClientHttpRequest

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

    重点:使用不同的RequestFactory返回具有不同功能的ClientHttpRequest 类型的实例对象,然后通过调用其 execute() 方法来得到ClientHttpResponse响应对象。

    在返回ClientHttpResponse类型对象的过程中具体要做些什么事情完全由ClientHttpRequest的实现类自我决定。

    3,RestOperations接口

    该接口主要是定义了一些访问方法,例如getForObject、getForEntity等,简要列举如下:

    public interface RestOperations {
      <T> T getForObject(String url, Class<T> responseType, Map<String, ?> uriVariables) throws RestClientException;
      HttpHeaders headForHeaders(String url, Map<String, ?> uriVariables) throws RestClientException;
      <T> T postForObject(String url, @Nullable Object request, Class<T> responseType,
      Map<String, ?> uriVariables) throws RestClientException;
      <T> ResponseEntity<T> exchange(RequestEntity<?> requestEntity, Class<T> responseType) throws RestClientException;
      <T> T execute(String url, HttpMethod method, @Nullable RequestCallback requestCallback,@Nullable ResponseExtractor<T> responseExtractor, Map<String, ?> uriVariables) throws RestClientException;
    }
    

    4,RestTemplate类

    在RestTemplate的构造方法中会初始化许多消息转换器(HttpMessageConverter),以及用于解析URL模板(字符串)的UriTemplateHandler类型对象(DefaultUriBuilderFactory),其它的都是对父级接口的实现。


    接下来我们根据一个方法调用来跟踪其执行流程

    从上可知,RestTemplate的实现原理其实还挺简单的,很多时候其默认的配置就已经够我们使用了,那么哪些地方可能是我们可以进行扩展时需要考虑的地方呢,或者我们要对其功能进行扩展时应该从哪里入手呢?

    RestTemplate中进行扩展最重要的地方就是ClientHttpRequestFactory与ClientHttpRequestInterceptor了。通过自定义ClientHttpRequestFactory我们可以使用apache Http Client或者okHttp组件来发起http的请求操作,同时返回我们自定义的ClientHttpRequest及ClientHttpResponse对象; 而通过自定义的ClientHttpRequestInterceptor对象,我们可以在发起请求的时候对请求进行拦截,对请求的参数等进行修改等。

    下面我们从一个请求发起开始来分析整个流程,假定我们调用RestTemplate的getForObject方法

    //调用RestTemplate的该方法发起请求
    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);
      return execute(url, HttpMethod.GET, requestCallback, responseExtractor, uriVariables);
    }
    
    public <T> T execute(String url, HttpMethod method, @Nullable RequestCallback requestCallback,@Nullable ResponseExtractor<T> responseExtractor, Object... uriVariables) throws RestClientException {
      //对URL模板字符串进行解析
      URI expanded = getUriTemplateHandler().expand(url, uriVariables);
      //执行请求【参照下面的方法】
      return doExecute(expanded, method, requestCallback, responseExtractor);
    }
    
    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 {
        //针对要访问的URL和使用的HTTP方法创建请求对象【参照下面的方法】
        ClientHttpRequest request = 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();
        }
      }
    }
    
    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() {
      List<ClientHttpRequestInterceptor> interceptors = getInterceptors();
      if (!CollectionUtils.isEmpty(interceptors)) {
        //如果有设置拦截器,则使用InterceptingClientHttpRequestFactory工厂对象
        ClientHttpRequestFactory factory = this.interceptingRequestFactory;
        if (factory == null) {
          factory = new InterceptingClientHttpRequestFactory(super.getRequestFactory(), interceptors);
          this.interceptingRequestFactory = factory;
        }
        return factory;
      } else {
        return super.getRequestFactory();
      }
    }
    

    InterceptingClientHttpRequestFactory类的实现如下

    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());
      }
    
       //重写父类的方法返回针对具有拦截器情况的InterceptingClientHttpRequest对象
      @Override
      protected ClientHttpRequest createRequest(URI uri, HttpMethod httpMethod, ClientHttpRequestFactory requestFactory) {
        return new InterceptingClientHttpRequest(requestFactory, this.interceptors, uri, httpMethod);
      }
    }
    

    InterceptingClientHttpRequest类的实现如下

    class InterceptingClientHttpRequest extends AbstractBufferingClientHttpRequest {
      private final ClientHttpRequestFactory requestFactory;
      private final List<ClientHttpRequestInterceptor> interceptors;
      private HttpMethod method;
      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
      public HttpMethod getMethod() {
        return this.method;
      }
    
      @Override
      public String getMethodValue() {
        return this.method.name();
      }
    
      @Override
      public URI getURI() {
        return this.uri;
      }
    
      @Override
      protected final ClientHttpResponse executeInternal(HttpHeaders headers, byte[] bufferedOutput) throws IOException {
        InterceptingRequestExecution requestExecution = new InterceptingRequestExecution();
        return requestExecution.execute(this, bufferedOutput);
      }
      //创建一个ClientHttpRequestExecution类型的内部类来执行所有拦截器并发起请求
      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);
          } else {
            //当所有拦截器都执行完成后便开始发起HTTP请求
            HttpMethod method = request.getMethod();
            Assert.state(method != null, "No standard HTTP method");
            //通过设置的requestFactory来创建ClientHttpRequest类型的对象并发起请求
            //可以通过改变requestFactory来改变默认的行为
            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();
          }
        }
      }
    }
    

    在调用execute()方法时会间接的调用executeInternal方法并返回。在该方法里面创建了一个InterceptingRequestExecution对象,InterceptingRequestExecution对象的execute方法在执行的过程中会被迭代的调用(被各个拦截器调用),直到所有的拦截器都执行完后才开始创建要执行HTTP请求的ClientHttpRequest对象,然后执行并返回结果。

    我们找一个BasicAuthorizationInterceptor拦截器看其内部实现

    public class BasicAuthorizationInterceptor implements ClientHttpRequestInterceptor {
      private final String username;
      private final String password;
    
      public BasicAuthorizationInterceptor(@Nullable String username, @Nullable String password) {
        Assert.doesNotContain(username, ":", "Username must not contain a colon");
        this.username = (username != null ? username : "");
        this.password = (password != null ? password : "");
      }
    
      @Override
      public ClientHttpResponse intercept(HttpRequest request, byte[] body, ClientHttpRequestExecution execution) throws IOException {
        //加上需要的请求头数据
        String token = Base64Utils.encodeToString((this.username + ":" + this.password).getBytes(StandardCharsets.UTF_8));
        request.getHeaders().add("Authorization", "Basic " + token);
        //继续执行后面的拦截器对象
        return execution.execute(request, body);
      }
    }
    

    重点:可见,RestTemplate在执行调用的时候主要就是经过了以下三步

    1. 使用ClientHttpRequestFactory类型对象创建ClientHttpRequest类型对象【例如可以执行拦截器的 InterceptingClientHttpRequest 】
    2. 执行ClientHttpRequest类型实例对象的execute()方法得到ClientHttpResponse类型的响应结果
    3. 对响应结果进行处理并返回给调用者

    小结

    通过以上的分析,应该已经可以很好的理解RestTemplate的执行原理了,我们也可以通过自定义RequestFactory和拦截器的方式来扩展其功能,例如使用RestTemplate完成客户端负载均衡等。最后提供一张较为完整的类图,供大家参考


    RestTemplate类图

    相关文章

      网友评论

        本文标题:SpringCloud解析一:RestTemplate源码分析

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