美文网首页
Feign源码学习(3)

Feign源码学习(3)

作者: 無式 | 来源:发表于2017-09-16 09:54 被阅读0次
    • 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错误做了单独处理。

    相关文章

      网友评论

          本文标题:Feign源码学习(3)

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