Loading...
墨滴

lyq

2021/11/05  阅读:29  主题:默认主题

Spring Cloud Netflix Ribbon源码解析(二)

基于Spring Cloud Hoxton.SR9版本


前言

接着上篇《Spring Cloud Netflix Ribbon源码解析(一)》,在上一篇中,在运行阶段,我们是直接进入LoadBalancerInterceptorintercept方法,然后一步步沿着主线脉络去分析的。那么这个方法又是怎么被调用的呢?今天我们就来看看,这个方法是怎么被调用到的。那么开始之前呢,我们需要找到入口位置,这个入口就是restTemplate.getForObject()方法,好了,我们进入这个方法,一探究竟吧。

源码分析

RestTemplate

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

通过查看源码可以发现调用自己的execute方法。

@Override
@Nullable
public <T> execute(String url, HttpMethod method, @Nullable RequestCallback requestCallback,
  @Nullable ResponseExtractor<T> responseExtractor, Object... uriVariables)
 throws RestClientException 
{

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

接着调用内部的doExecute方法。

@Nullable
protected <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 {
  //创建ClientHttpRequest对象
  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();
  }
 }
}

这里有2行关键的代码,分别是:createRequest(url, method)request.execute(),那么首先我们需要看看createRequest方法返回的ClientHttpRequest对象的具体实现是哪个。进入createRequest方法内部:

HttpAccessor

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

点击会进入父类(HttpAccessor)的createRequest方法,这里先插入一下类图,方便理解:

通过代码可以看到这一行代码getRequestFactory().createRequest(url, method);,首先通过getRequestFactory()方法得到requestFactory,然后调用目标的createRequest方法,所以我们需要先知道这个requestFactory,具体是哪一个。

通过上图可以发现,一个是调用它本身的getRequestFactory方法,一个是调用子类的方法,很明显,这里调用的是子类的方法,那么点击进入子类中。

InterceptingHttpAccessor

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

首先调用getInterceptors()方法获取拦截器集合,那么我们先看看这些拦截器是怎么来的,点进去看一下:

public List<ClientHttpRequestInterceptor> getInterceptors() {
 return this.interceptors;
}

返回当前类中interceptors对象,那么这个interceptors是在哪里赋值的呢,在当前类的顶部我们会发现这么一行代码:

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

创建了一个空集合,那么看看到底是在哪里被初始化赋值的,往下看,可以看到这个类有一个setInterceptors方法:

public void setInterceptors(List<ClientHttpRequestInterceptor> interceptors) {
 Assert.noNullElements(interceptors, "'interceptors' must not contain null elements");
 // Take getInterceptors() List as-is when passed in here
 if (this.interceptors != interceptors) {
  this.interceptors.clear();
  this.interceptors.addAll(interceptors);
  AnnotationAwareOrderComparator.sort(this.interceptors);
 }
}

上面的interceptors集合就是在这里被赋值的,那么这个setInterceptors方法在哪里被调用的呢?还记得上一篇中在LoadBalancerAutoConfiguration配置类中的代码吗?

@Bean
@ConditionalOnMissingBean
public RestTemplateCustomizer restTemplateCustomizer(
  final LoadBalancerInterceptor loadBalancerInterceptor)
 
{
 return restTemplate -> {
  List<ClientHttpRequestInterceptor> list = new ArrayList<>(
    restTemplate.getInterceptors());
  list.add(loadBalancerInterceptor);
  //答案就在这里
  restTemplate.setInterceptors(list);
 };
}

所以前面说的List<ClientHttpRequestInterceptor> interceptors = getInterceptors();结果肯定不会为空,好的,回到上一步,由于interceptors肯定不为空,所以getRequestFactory方法返回的是InterceptingClientHttpRequestFactory。再退到ClientHttpRequest request=getRequestFactory().createRequest(url, method);方法。最终调用的就是InterceptingClientHttpRequestFactory类的createRequest方法:

InterceptingClientHttpRequestFactory

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

返回的ClientHttpRequest的具体实现就是InterceptingClientHttpRequest对象。ok,那么我们再回到RestTemplatedoExecute方法,看一下内部的request.execute()方法调用情况。为了方便阅读,先插入一张类图,如下:

通过类图可以发现,调用的其实是父类中的execute方法。那么进入AbstractClientHttpRequestexecute方法:

@Override
public final ClientHttpResponse execute() throws IOException {
 assertNotExecuted();
 ClientHttpResponse result = executeInternal(this.headers);
 this.executed = true;
 return result;
}

内部会调用模板方法executeInternal,一路向下,最终会调用InterceptingClientHttpRequestexecuteInternal方法:

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

然后调用InterceptingRequestExecutionexecute方法:

InterceptingRequestExecution

@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 {
  HttpMethod method = request.getMethod();
  Assert.state(method != null"No standard HTTP method");
  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();
 }
}

上面的代码中有个this.iterator,我们先不管iterator是啥,但从字面上我们可以看出ClientHttpRequestInterceptor这玩意给我们存的应该是一个客户端请求拦截器,而且通过debugger可以发现这个拦截器一定会包含我上一篇中分析说到的LoadBalancerInterceptor,这样一步步的看就跟上一篇幅说的连上了。

好了,说到这里,我们今天的源码之旅就要结束了,感谢您的阅读。下一篇我们会继续介绍关于Ribbon的其他内容,敬请期待!

更多原创文章,请扫码关注我的微信公众号
更多原创文章,请扫码关注我的微信公众号

lyq

2021/11/05  阅读:29  主题:默认主题

作者介绍

lyq