spring cloud feign - 动态主线

本文接上一篇静态主线,来继续看feign是如何进行网络调用的。

上文说到将所有的方法与模板都绑定到feign.ReflectiveFeign.FeignInvocationHandler代理类上了。这篇就从这块说起:
feign.ReflectiveFeign.FeignInvocationHandler#invoke调用,代码如下:

@Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
      //对Object的方法进行处理,已省略

    //dispatch就是Map类型,会根据方法交给对应的MethodHandler
      return dispatch.get(method).invoke(args);
    }

下一步跳转到feign.SynchronousMethodHandler#invoke中:

@Override
  public Object invoke(Object[] argv) throws Throwable {
    //构建RequestTemplate,buildTemplateFromArgs为RequestTemplate.Factory的实例
    RequestTemplate template = buildTemplateFromArgs.create(argv);
  //重试机制  
  Retryer retryer = this.retryer.clone();
    while (true) {
      try {
        return executeAndDecode(template);
      } catch (RetryableException e) {
        retryer.continueOrPropagate(e);
        if (logLevel != Logger.Level.NONE) {
          logger.logRetry(metadata.configKey(), logLevel);
        }
        continue;
      }
    }
  }
@Override
    public RequestTemplate create(Object[] argv) {
      RequestTemplate mutable = new RequestTemplate(metadata.template());
      if (metadata.urlIndex() != null) {
        int urlIndex = metadata.urlIndex();
        checkArgument(argv[urlIndex] != null, "URI parameter %s was null", urlIndex);
        mutable.insert(0, String.valueOf(argv[urlIndex]));
      }
      Map varBuilder = new LinkedHashMap();
    //填充参数到变量map中
      for (Entry> entry : metadata.indexToName().entrySet()) {
        int i = entry.getKey();
        Object value = argv[entry.getKey()];
        if (value != null) { // Null values are skipped.
          if (indexToExpander.containsKey(i)) {
        //转换参数中的值为需要的类型
            value = expandElements(indexToExpander.get(i), value);
          }
          for (String name : entry.getValue()) {
            varBuilder.put(name, value);
          }
        }
      }
    //解析模板路径
      RequestTemplate template = resolve(argv, mutable, varBuilder);
      if (metadata.queryMapIndex() != null) {
        // add query map parameters after initial resolve so that they take
        // precedence over any predefined values
        template = addQueryMapQueryParameters((Map) argv[metadata.queryMapIndex()], template);
      }

      if (metadata.headerMapIndex() != null) {
        template = addHeaderMapHeaders((Map) argv[metadata.headerMapIndex()], template);
      }

      return template;
    }

RequestTemplate resolve(Map unencoded, Map alreadyEncoded) {
    //替换query中的参数,即?后面拼接的参数
    replaceQueryValues(unencoded, alreadyEncoded);
    Map encoded = new LinkedHashMap();
    //参数编码
    for (Entry entry : unencoded.entrySet()) {
      final String key = entry.getKey();
      final Object objectValue = entry.getValue();
      String encodedValue = encodeValueIfNotEncoded(key, objectValue, alreadyEncoded);
      encoded.put(key, encodedValue);
    }
    //此处挨个字符查找{,拼接值,忽略和}的中间部分,拼接}后面部分
    String resolvedUrl = expand(url.toString(), encoded).replace("+", "%20");
    if (decodeSlash) {
      resolvedUrl = resolvedUrl.replace("%2F", "/");
    }
    url = new StringBuilder(resolvedUrl);

    Map> resolvedHeaders = new LinkedHashMap>();
    //处理head部分
    for (String field : headers.keySet()) {
      Collection resolvedValues = new ArrayList();
      for (String value : valuesOrEmpty(headers, field)) {
        String resolved = expand(value, unencoded);
        resolvedValues.add(resolved);
      }
      resolvedHeaders.put(field, resolvedValues);
    }
    headers.clear();
    headers.putAll(resolvedHeaders);
    if (bodyTemplate != null) {
      body(urlDecode(expand(bodyTemplate, encoded)));
    }
    return this;
  }

执行请求,并对响应进行解码的过程,代码feign.SynchronousMethodHandler#executeAndDecode如下:

 Object executeAndDecode(RequestTemplate template) throws Throwable {
//拼接完整的request请求    
Request request = targetRequest(template);

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

    Response response;
    long start = System.nanoTime();
    try {
      //由LoadBalancerFeignClient发送请求,默认是连接1000毫秒,读超时30000毫秒。
      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();
      }
      //对响应解码,已省略

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

获取feign配置并发送请求,下面是org.springframework.cloud.openfeign.ribbon.LoadBalancerFeignClient#execute代码:

@Override
    public Response execute(Request request, Request.Options options) throws IOException {
        try {
            URI asUri = URI.create(request.url());
            String clientName = asUri.getHost();
            URI uriWithoutHost = cleanUrl(request.url(), clientName);
            FeignLoadBalancer.RibbonRequest ribbonRequest = new FeignLoadBalancer.RibbonRequest(
                    this.delegate, request, uriWithoutHost);

            IClientConfig requestConfig = getClientConfig(options, clientName);
            return lbClient(clientName).executeWithLoadBalancer(ribbonRequest,
                    requestConfig).toResponse();
        }
        catch (ClientException e) {
            IOException io = findIOException(e);
            if (io != null) {
                throw io;
            }
            throw new RuntimeException(e);
        }
    }
public T executeWithLoadBalancer(final S request, final IClientConfig requestConfig) throws ClientException {
        LoadBalancerCommand command = buildLoadBalancerCommand(request, requestConfig);

        try {
            return command.submit(
                new ServerOperation() {
                    @Override
                    public Observable call(Server server) {
      //构建HTTP的url,并在最后用HTTPConnection完成请求
                        URI finalUri = reconstructURIWithServer(server, request.getUri());
                        S requestForServer = (S) request.replaceUri(finalUri);
                        try {
                            return Observable.just(AbstractLoadBalancerAwareClient.this.execute(requestForServer, requestConfig));
                        } 
                        catch (Exception e) {
                            return Observable.error(e);
                        }
                    }
                })
                .toBlocking()
                .single();
        } catch (Exception e) {
            Throwable t = e.getCause();
            if (t instanceof ClientException) {
                throw (ClientException) t;
            } else {
                throw new ClientException(e);
            }
        }
        
    }

你可能感兴趣的:(spring cloud feign - 动态主线)