美文网首页
spring cloud feign - 动态主线

spring cloud feign - 动态主线

作者: 靈08_1024 | 来源:发表于2019-02-19 10:02 被阅读2次

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

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

    @Override
        public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
          //对Object的方法进行处理,已省略
    
        //dispatch就是Map<Method, MethodHandler>类型,会根据方法交给对应的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<String, Object> varBuilder = new LinkedHashMap<String, Object>();
        //填充参数到变量map中
          for (Entry<Integer, Collection<String>> 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<String, Object>) argv[metadata.queryMapIndex()], template);
          }
    
          if (metadata.headerMapIndex() != null) {
            template = addHeaderMapHeaders((Map<String, Object>) argv[metadata.headerMapIndex()], template);
          }
    
          return template;
        }
    
    
    RequestTemplate resolve(Map<String, ?> unencoded, Map<String, Boolean> alreadyEncoded) {
        //替换query中的参数,即?后面拼接的参数
        replaceQueryValues(unencoded, alreadyEncoded);
        Map<String, String> encoded = new LinkedHashMap<String, String>();
        //参数编码
        for (Entry<String, ?> 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<String, Collection<String>> resolvedHeaders = new LinkedHashMap<String, Collection<String>>();
        //处理head部分
        for (String field : headers.keySet()) {
          Collection<String> resolvedValues = new ArrayList<String>();
          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<T> command = buildLoadBalancerCommand(request, requestConfig);
    
            try {
                return command.submit(
                    new ServerOperation<T>() {
                        @Override
                        public Observable<T> 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 - 动态主线

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