zoukankan      html  css  js  c++  java
  • Feign的调用流程

    Feign的调用流程

    动态代理的入口

    前面已经分析过了创建的代理是FeignInvocationHandler,那我们就打断点,停在它的反射方法上,看看到底做了什么。

        @Override
        public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
          if ("equals".equals(method.getName())) {
            try {
              Object otherHandler =
                  args.length > 0 && args[0] != null ? Proxy.getInvocationHandler(args[0]) : null;
              return equals(otherHandler);
            } catch (IllegalArgumentException e) {
              return false;
            }
          } else if ("hashCode".equals(method.getName())) {
            return hashCode();
          } else if ("toString".equals(method.getName())) {
            return toString();
          }
    
          return dispatch.get(method).invoke(args);
        }
    
    

    dispatch此处就是之前封装的5个SynchronousMethodHandler方法的集合,这里更加方法去获取,然后调用invoke方法。来到了SynchronousMethodHandler这个方法。

      @Override
      public Object invoke(Object[] argv) throws Throwable {
        RequestTemplate template = buildTemplateFromArgs.create(argv);
        Options options = findOptions(argv);
        Retryer retryer = this.retryer.clone();
        while (true) {
          try {
            return executeAndDecode(template, options);
          } catch (RetryableException e) {
            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;
          }
        }
      }
    

    第一行首先会创建出一个template的,它的结果如下图:

    image-20211020111759451

    最终把上面获取到的2个变量带到了executeAndDecode方法,这个方法才是执行和解码的方法。

      Object executeAndDecode(RequestTemplate template, Options options) 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 {
           //来到了这里,无论是负载均衡还是请求响应都是这边完成的,那我们就点进去看看。
          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);
    
    
        if (decoder != null)
          return decoder.decode(response, metadata.returnType());
    
        CompletableFuture<Object> resultFuture = new CompletableFuture<>();
        asyncResponseHandler.handleResponse(resultFuture, metadata.configKey(), response,
            metadata.returnType(),
            elapsedTime);
    
        try {
          if (!resultFuture.isDone())
            throw new IllegalStateException("Response handling not done");
    
          return resultFuture.join();
        } catch (CompletionException e) {
          Throwable cause = e.getCause();
          if (cause != null)
            throw cause;
          throw e;
        }
      }
    

    image-20211020134735701

    image-20211019163335889

    Feign是如何实现负载均衡的

    image-20211019163652954

    image-20211020134908197

    先进入到前面的lbClient方法,返回一个FeignLoadBalancer,说明这里和ribbon结合了。

    	private FeignLoadBalancer lbClient(String clientName) {
    		return this.lbClientFactory.create(clientName);
    	}
    

    此处调用了一个create方法,那就进去看看。

    image-20211019164151403

    注意这里的factory,其实就是SpringClientFactory,从它里面获取了lb,lb里面包含了注册的服务清单,然后再把它放到本地的缓存当中。

    image-20211019164405363

    接着就会执行,现在它的sumbit方法中打一个断点:

    image-20211020140024852

    发现里面会执行一个selectServer()方法,肯定是这个里面选择了服务

    image-20211020140146188

    在点进去看看,于是就找到了ribbon中熟悉的方法了,就是这里选择了那个服务

    image-20211020140513907

    选择好了那个服务,就继续放下走,开始这边拼接ip和url了

    image-20211019164601834

    会把选择的ip和后面请求的url都传进来。

    image-20211020135733168

    在其父类的reconstructURIWithServer方法中完成了拼接,如下图:

    image-20211020135847867

    后面就是请求响应和解码了

  • 相关阅读:
    Android——另外一种增删查改的方式(ContentProvider常用)
    VS2012下基于Glut OpenGL glScissor示例程序:
    JAXP的SAX解析
    38岁老男孩个人建站方向求教
    [置顶] 某大型银行深化系统技术方案之十三:服务层之服务接口模式
    比特币人必知术语
    ok6410 u-boot-2012.04.01移植二修改源码支持单板
    最近修bug的一点感悟
    小智慧24
    redis beforesleep
  • 原文地址:https://www.cnblogs.com/dalianpai/p/15428623.html
Copyright © 2011-2022 走看看