Feign源码学习(3)

  • ReflectiveFeign中看到实现将接口方法解析成Rest请求的核心逻辑在这行代码:
    //核心逻辑入口,反射解析目标Class,得到MethodHandler集合
    Map<String, MethodHandler> nameToHandler = targetToHandlersByName.apply(target);
  • MethodHandler接口的定义为:
  interface MethodHandler {
    Object invoke(Object[] argv) throws Throwable;
  }
  • 只有一个invoke方法,和Proxy的定义类似。
  • 实现Rest请求的实现类为SynchronousMethodHandler,实现方法为:
  @Override
  public Object invoke(Object[] argv) throws Throwable {
    //根据输入参数组装成HTTP请求模版
    RequestTemplate template = buildTemplateFromArgs.create(argv);
    Retryer retryer = this.retryer.clone();  //重试策略
    while (true) {
      try {
        //执行HTTP请求并解析结果,返回
        return executeAndDecode(template);
      } catch (RetryableException e) {
        retryer.continueOrPropagate(e);  //重试策略
        if (logLevel != Logger.Level.NONE) {
          logger.logRetry(metadata.configKey(), logLevel);
        }
        continue;
      }
    }
  }
  • RequestTemplate:封装REST请求模版,包括HTTP协议中请求需要的信息。
  • buildTemplateFromArgs.create(argv):输入参数有可能是HTTP中的PathParameterHeaderBody等参数。每个参数按顺序,代表的意义是在API接口定义时,由形参上的标签(Annotation)决定的。
  • executeAndDecode(template):执行并解析HTTP结果,这个类的核心逻辑:
  Object executeAndDecode(RequestTemplate template) throws Throwable {
    //生成请求实例
    Request request = targetRequest(template);

    if (logLevel != Logger.Level.NONE) {
      logger.logRequest(metadata.configKey(), logLevel, request);
    }

    Response response;
    long start = System.nanoTime();
    try {
      //发起REST请求,得到响应
      response = client.execute(request, options);
      // ensure the request is set. TODO: remove in Feign 10
      response.toBuilder().request(request).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);
        // ensure the request is set. TODO: remove in Feign 10
        response.toBuilder().request(request).build();
      }
      if (Response.class == metadata.returnType()) {
        if (response.body() == null) {
          return response;
        }
        if (response.body().length() == null ||
                response.body().length() > MAX_RESPONSE_BUFFER_SIZE) {
          shouldClose = false;
          return response;
        }
        // Ensure the response body is disconnected
        byte[] bodyData = Util.toByteArray(response.body().asInputStream());
        return response.toBuilder().body(bodyData).build();
      }

      //请求成功的响应处理
      if (response.status() >= 200 && response.status() < 300) {
        if (void.class == metadata.returnType()) {
          return null;
        } else {
          //解析成需要的对象返回
          return decode(response);
        }
      } 
      //404的响应单独处理
      else if (decode404 && response.status() == 404 && void.class != metadata.returnType()) {
        return decode(response);
      } else {
        //错误响应时,转换为指定的异常对象
        throw errorDecoder.decode(metadata.configKey(), response);
      }
    } catch (IOException e) {
      if (logLevel != Logger.Level.NONE) {
        logger.logIOException(metadata.configKey(), logLevel, e, elapsedTime);
      }
      throw errorReading(request, response, e);
    } finally {
      if (shouldClose) {
        //关闭输入流
        ensureClosed(response.body());
      }
    }
  }
  • RequestResponseFeignREST请求响应的封装。
  • client.execute(request, options)HTTP请求实际发生的步骤,clientHTTP请求客户端的抽象,实际使用的HTTP框架是由使用者定义,支持的包括有:Java原生,OkHttp, ApacheHttpClient等。
  • return decode(response):成功的响应内容转换成API定义的出参对象。
  • if (decode404 && response.status() == 404 && void.class != metadata.returnType()):在REST规范中,一般将找不到资源实现为返回404 NOT FOUND错误。因此404错误被认为是一种业务范畴里的正常响应,所以Feign404错误做了单独处理。
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容

  • Spring Cloud为开发人员提供了快速构建分布式系统中一些常见模式的工具(例如配置管理,服务发现,断路器,智...
    卡卡罗2017阅读 135,107评论 19 139
  • 国家电网公司企业标准(Q/GDW)- 面向对象的用电信息数据交换协议 - 报批稿:20170802 前言: 排版 ...
    庭说阅读 11,248评论 6 13
  • 一说到REST,我想大家的第一反应就是“啊,就是那种前后台通信方式。”但是在要求详细讲述它所提出的各个约束,以及如...
    时待吾阅读 3,483评论 0 19
  • 这个营还有1天就要结束了。假如你是这个群战略顾问——如果我们将来能一起做点什么事,你希望是什么?————#超级个体...
    Katrina程阅读 197评论 0 0
  • 小时候家住农村,第一次看电影是在1957年的春节过后,那天正好是正月初八,因为是人日子吃面条的第二天所以记得特别清...
    扶青阅读 854评论 3 7