本系列代码地址:https://github.com/JoJoTec/sp...

接下来,咱们开始剖析 OpenFeign 同步环境下的生命周期的第二局部,应用 SynchronousMethodHandler 进行理论调用,其流程能够总结为:

  1. 调用代理类的办法理论调用的是后面一章中生成的 InvocationHandlerinvoke 办法。
  2. 默认实现是查问 Map<Method, MethodHandler> methodToHandler 找到对应的 MethodHandler 进行调用,对于同步 Feign,其实就是 SynchronousMethodHandler
  3. 对于 SynchronousMethodHandler:

    1. 应用后面一章剖析创立的创立的申请模板工厂 RequestTemplate.Factory,创立申请模板 RequestTemplate
    2. 读取 Options 配置
    3. 应用配置的 Retryer 创立新的 Retryer
    4. 执行申请并将响应反序列化 - executeAndDecode:
    1. 如果配置了 RequestInterceptor,则执行每一个 RequestInterceptor
    2. 将申请模板 RequestTemplate 转化为理论申请 Request
    3. 通过 Client 执行 Request
    4. 如果响应码是 2XX,应用 Decoder 解析 Response
    5. 如果响应码是 404,并且在后面一章介绍的配置中配置了 decode404 为 true, 应用 Decoder 解析 Response
    6. 对于其余响应码,应用 errorDecoder 解析,能够本人实现 errorDecoder 抛出 RetryableException 来走入重试逻辑
    7. 如果以上步骤抛出 IOException,间接封装成 RetryableException 抛出

      1. 如果第 4 步抛出 RetryableException,则应用第三步创立的 Retryer 判断是否重试,如果须要重试,则从新走第 4 步,否则,抛出异样。

给出这个流程后,咱们来详细分析

OpenFeign的生命周期-进行调用源码剖析

后面一章的最初,咱们曾经从源码中看到了这一章结尾提到的流程的前两步,咱们间接从第三步开始剖析。

SynchronousMethodHandler

public Object invoke(Object[] argv) throws Throwable {    //应用后面一章剖析创立的创立的申请模板工厂 `RequestTemplate.Factory`,创立申请模板 `RequestTemplate`。    RequestTemplate template = buildTemplateFromArgs.create(argv);    //读取 Options 配置    Options options = findOptions(argv);    //应用配置的 Retryer 创立新的 Retryer    Retryer retryer = this.retryer.clone();    while (true) {      try {        //执行申请并将响应反序列化        return executeAndDecode(template, options);      } catch (RetryableException e) {        //如果抛出 RetryableException,则应用 retryer 判断是否重试,如果须要重试,则持续申请即重试,否则,抛出异样。        try {          retryer.continueOrPropagate(e);        } catch (RetryableException th) {          Throwable cause = th.getCause();          if (propagationPolicy == UNWRAP && cause != null) {            throw cause;          } else {            throw th;          }        }        if (logLevel != Logger.Level.NONE) {          logger.logRetry(metadata.configKey(), logLevel);        }        continue;      }    }  }

对于 executeAndDecode 其中的源码,为了兼容异步 OpenFeign 兼容 CompletableFuture 的个性,做了一些兼容性批改导致代码比拟难以了解,因为咱们这里不关怀异步 Feign,所以咱们将这块代码还原回来,在这里展现:

这个批改对应的 Issue 和 PullRequest 是:

  • Non-blocking I/O support
  • issue 361 - async feign variant supporting CompleteableFutures
Request targetRequest(RequestTemplate template) {    //如果配置了 RequestInterceptor,则执行每一个 RequestInterceptor    for (RequestInterceptor interceptor : requestInterceptors) {      interceptor.apply(template);    }    //将申请模板 RequestTemplate 转化为理论申请 Request    return target.apply(template);}Object executeAndDecode(RequestTemplate template, Options options) throws Throwable {    Request request = targetRequest(template);    if (logLevel != Logger.Level.NONE) {      logger.logRequest(metadata.configKey(), logLevel, request);    }    Response response;    long start = System.nanoTime();    try {      //通过 Client 执行 Request      response = client.execute(request, options);      // ensure the request is set. TODO: remove in Feign 12      response = response.toBuilder()          .request(request)          .requestTemplate(template)          .build();    } catch (IOException e) {      if (logLevel != Logger.Level.NONE) {        logger.logIOException(metadata.configKey(), logLevel, e, elapsedTime(start));      }      throw errorExecuting(request, e);    }    long elapsedTime = TimeUnit.NANOSECONDS.toMillis(System.nanoTime() - start);    boolean shouldClose = true;    try {      if (logLevel != Logger.Level.NONE) {        response =            logger.logAndRebufferResponse(metadata.configKey(), logLevel, response, elapsedTime);      }      //如果响应码是 2XX,应用 Decoder 解析 Response      if (response.status() >= 200 && response.status() < 300) {        if (void.class == metadata.returnType()) {          return null;        } else {          Object result = decode(response);          shouldClose = closeAfterDecode;          return result;        }      } else if (decode404 && response.status() == 404 && void.class != metadata.returnType()) {        //如果响应码是 404,并且在后面一章介绍的配置中配置了 decode404 为 true, 应用 Decoder 解析 Response        Object result = decode(response);        shouldClose = closeAfterDecode;        return result;      } else {        //对于其余响应码,应用 errorDecoder 解析,能够本人实现 errorDecoder 抛出 RetryableException 来走入重试逻辑        throw errorDecoder.decode(metadata.configKey(), response);      }    } catch (IOException e) {      if (logLevel != Logger.Level.NONE) {        logger.logIOException(metadata.configKey(), logLevel, e, elapsedTime);      }      //如果抛出 IOException,间接封装成 RetryableException 抛出      throw errorReading(request, response, e);    } finally {      if (shouldClose) {        ensureClosed(response.body());      }    }}static FeignException errorReading(Request request, Response response, IOException cause) {    return new FeignException(        response.status(),        format("%s reading %s %s", cause.getMessage(), request.httpMethod(), request.url()),        request,        cause,        request.body(),        request.headers());}

这样,咱们就剖析完 OpenFeign 的生命周期

咱们这一节具体介绍了 OpenFeign 进行调用的具体流程。接下来咱们将开始介绍,spring-cloud-openfeign 外面,是如何定制 OpenFeign 的组件并粘合的。

微信搜寻“我的编程喵”关注公众号,每日一刷,轻松晋升技术,斩获各种offer