优秀的编程知识分享平台

网站首页 > 技术文章 正文

spring-web5.0里的RestTemplate实现原理

nanyue 2024-09-08 06:07:57 技术文章 7 ℃

一、RestOperations

定义符合rest规范的接口,包含 get post head delete等一系列接口方法很多,最终调用的都是 execute方法。

二、HttpAccessor

抽象父类http访问器,通过 ClientHttpRequestFactory 创建 ClientHttpRequest

public abstract class HttpAccessor {
   protected final Log logger = LogFactory.getLog(getClass());

   private ClientHttpRequestFactory requestFactory = new SimpleClientHttpRequestFactory();

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

}

三、InterceptingHttpAccessor

具有拦截器功能的HttpAccessor ,相当于是一种装饰者设计模式

public abstract class InterceptingHttpAccessor extends HttpAccessor {

   private final List<ClientHttpRequestInterceptor> interceptors = new ArrayList<>();

   @Nullable
   private volatile ClientHttpRequestFactory interceptingRequestFactory;
   // 维护一个拦截器列表,并且将拦截器排序
   public void setInterceptors(List<ClientHttpRequestInterceptor> interceptors) {
      // Take getInterceptors() List as-is when passed in here
      if (this.interceptors != interceptors) {
         this.interceptors.clear();
         this.interceptors.addAll(interceptors);
         AnnotationAwareOrderComparator.sort(this.interceptors);
      }
   }
    // 如果有拦截器,则使用 InterceptingClientHttpRequestFactory,否则 使用普通的 ClientHttpRequestFactory
   @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();
      }
   }

}

四、RestTemplate

RestTemplate是一个在 jdk的httpUrlConnection,apache HttpComponents,okhttp3等其他的工具类库之上封装的一个简单且有模板方法api的同步执行http请求的客户端。

RestTemplate为常见场景提供模板,并且为少见场景提供了exchange和execute接口。


首先从继承关系可以看出 RestTemplate 实现 RestOperations的一系列get post 等接口, 继承 InterceptingHttpAccessor的拦截器功能。

public class RestTemplate extends InterceptingHttpAccessor implements RestOperations {

   private final List<HttpMessageConverter<?>> messageConverters = new ArrayList<>();

   private ResponseErrorHandler errorHandler = new DefaultResponseErrorHandler();

   private UriTemplateHandler uriTemplateHandler = new DefaultUriBuilderFactory();

   private final ResponseExtractor<HttpHeaders> headersExtractor = new HeadersExtractor();

}

4.1、成员变量

1、messageConverters

HttpMessageConverter消息转换器集合

1、在发起http请求之前,将请求体参数对象进行转换序列化,写进ClientHttpRequest对象

2、调用http请求之后,从ClientHttpResponse中拿到响应体,转换得到对应的Class对象

2、errorHandler

用于解析Response响应如果发生错误(例如statusCode是404 500等一系列错误码)时,执行errorHandler逻辑

3、uriTemplateHandler

uri模板处理器,例如url会写成http://host:port/get/{name}这种,然后传入参数name=11,通过uriTemplateHandler会解析转换成完整的路径 http://host:port/get/11

4、headersExtractor

针对 head或者option请求时,用于从ClientHttpResponse从提取header信息

4.2、成员方法

只分析常用的get和post方法

ForObject和ForEntity实现基本一样

ForObject返回业务上的responseType

ForEntity返回的是ResponseEntity,需要进一步使用ResponseEntity.getBody()才能得到 responseType

public <T> T getForObject(String url, Class<T> responseType, Object... uriVariables) throws RestClientException {
   RequestCallback requestCallback = acceptHeaderRequestCallback(responseType); // 创建一个AcceptHeaderRequestCallback 
   HttpMessageConverterExtractor<T> responseExtractor =
         new HttpMessageConverterExtractor<>(responseType, getMessageConverters(), logger);// 创建响应消息提取器(通过消息转换器集合)
   return execute(url, HttpMethod.GET, requestCallback, responseExtractor, uriVariables);
}

public <T> ResponseEntity<T> getForEntity(String url, Class<T> responseType, Object... uriVariables)
      throws RestClientException {

   RequestCallback requestCallback = acceptHeaderRequestCallback(responseType);
   ResponseExtractor<ResponseEntity<T>> responseExtractor = responseEntityExtractor(responseType);
   return nonNull(execute(url, HttpMethod.GET, requestCallback, responseExtractor, uriVariables));
}
public <T> T postForObject(String url, @Nullable Object request, Class<T> responseType,
      Object... uriVariables) throws RestClientException {

   RequestCallback requestCallback = httpEntityCallback(request, responseType); //创建一个HttpEntityRequestCallback 
   HttpMessageConverterExtractor<T> responseExtractor =
         new HttpMessageConverterExtractor<>(responseType, getMessageConverters(), logger);
   return execute(url, HttpMethod.POST, requestCallback, responseExtractor, uriVariables);
}
public <T> ResponseEntity<T> postForEntity(String url, @Nullable Object request,
      Class<T> responseType, Object... uriVariables) throws RestClientException {

   RequestCallback requestCallback = httpEntityCallback(request, responseType);
   ResponseExtractor<ResponseEntity<T>> responseExtractor = responseEntityExtractor(responseType);
   return nonNull(execute(url, HttpMethod.POST, requestCallback, responseExtractor, uriVariables));
}

3、doExecute (最终调用的方法)

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 {
     //1、真正的ClientHttpRequestFactory创建真正的ClientHttpRequest
      ClientHttpRequest request = createRequest(url, method); 
      if (requestCallback != null) {
        // 2、request回调处理
         requestCallback.doWithRequest(request); 
      }
     //3、真正的request发起http请求调用
      response = request.execute();
     //4、处理ClientHttpResponse,主要是errorHandler
      handleResponse(url, method, response);
     //5、从response中提取结果(转换成ResponseType)
      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();
      }
   }
}

4.3、RequestCallback

回调接口,可以操纵 请求头和请求体

4.4、AcceptHeaderRequestCallback

设置客户端希望接受的数据格式

4.5、HttpEntityRequestCallback

设置客户端此次发送的数据的数据格式

4.6、ResponseEntityResponseExtractor

将ClientHttpResponse转换成 ResponseEntity

private class ResponseEntityResponseExtractor<T> implements ResponseExtractor<ResponseEntity<T>> {

  // 相当于采用适配模式封装了HttpMessageConverterExtractor
   @Nullable
   private final HttpMessageConverterExtractor<T> delegate; 

   public ResponseEntityResponseExtractor(@Nullable Type responseType) {
      if (responseType != null && Void.class != responseType) {
         this.delegate = new HttpMessageConverterExtractor<>(responseType, getMessageConverters(), logger);
      }
      else {
         this.delegate = null;
      }
   }

  // 将HttpMessageConverterExtractor转换后的responseType对象 包装成了ResponseEntity
   @Override
   public ResponseEntity<T> extractData(ClientHttpResponse response) throws IOException {
      if (this.delegate != null) {
         T body = this.delegate.extractData(response); 
         return ResponseEntity.status(response.getRawStatusCode()).headers(response.getHeaders()).body(body);
      }
      else {
         return ResponseEntity.status(response.getRawStatusCode()).headers(response.getHeaders()).build();
      }
   }
}

4.7、HttpMessageConverterExtractor

将ClientHttpResponse返回的body响应体 从字节流 通过 HttpMessageConverter转换器集合 转换成 对应的 ResponseType 对象

五、总结

RestTemplate没有提供新的http请求调用方式,还是基于spring-web5.0里的http客户端模型之上做了适配,提供多种模板进行访问,对请求参数和返回参数进行处理,并没有特别新的东西。

最近发表
标签列表