Spring中Feign的调用流程详解

 更新时间:2023年11月21日 09:06:00   作者:dalianpai  
这篇文章主要介绍了Spring中Feign的调用流程详解,分析过了创建的代理是FeignInvocationHandler,那我们就打断点,停在它的反射方法上,看看到底做了什么,需要的朋友可以参考下

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

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

到此这篇关于Spring中Feign的调用流程详解的文章就介绍到这了,更多相关Feign的调用流程内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

相关文章

  • 快速解决List集合add元素,添加多个对象出现重复的问题

    快速解决List集合add元素,添加多个对象出现重复的问题

    这篇文章主要介绍了快速解决List集合add元素,添加多个对象出现重复的问题,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧
    2020-08-08
  • Java I/O流实例之简历替换

    Java I/O流实例之简历替换

    流是一种抽象概念,它代表了数据的无结构化传递。。用来进行输入输出操作的流就称为IO流。换句话说,IO流就是以流的方式进行输入输出
    2021-09-09
  • Java线程组操作实例分析

    Java线程组操作实例分析

    这篇文章主要介绍了Java线程组操作,结合实例形式分析了ThreadGroup类创建与使用线程组相关操作技巧,需要的朋友可以参考下
    2019-09-09
  • 浅谈java中的TreeMap 排序与TreeSet 排序

    浅谈java中的TreeMap 排序与TreeSet 排序

    下面小编就为大家带来一篇浅谈java中的TreeMap 排序与TreeSet 排序。小编觉得挺不错的,现在就分享给大家,也给大家做个参考。一起跟随小编过来看看吧
    2016-12-12
  • mybatis的ParamNameResolver参数名称解析

    mybatis的ParamNameResolver参数名称解析

    这篇文章主要为大家介绍了mybatis的ParamNameResolver参数名称解析,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪
    2023-08-08
  • spring boot 配置freemarker及如何使用freemarker渲染页面

    spring boot 配置freemarker及如何使用freemarker渲染页面

    springboot中自带的页面渲染工具为thymeleaf 还有freemarker这两种模板引擎,本文重点给大家介绍spring boot 配置freemarker及如何使用freemarker渲染页面,感兴趣的朋友一起看看吧
    2023-10-10
  • mybatis plus saveOrUpdate实现有重复数据就更新,否则新增方式

    mybatis plus saveOrUpdate实现有重复数据就更新,否则新增方式

    这篇文章主要介绍了mybatis plus saveOrUpdate实现有重复数据就更新,否则新增方式,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教
    2023-12-12
  • eclipse输出Hello World的实现方法

    eclipse输出Hello World的实现方法

    这篇文章主要介绍了eclipse输出Hello World的实现方法,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2020-11-11
  • java this super使用方法详解

    java this super使用方法详解

    Java中this、super关键字的用法简单说明:super是Java语言的保留字,用来指向类的超类,本文将详细介绍,需要的朋友可以参考下
    2012-12-12
  • Java中logback 自动刷新不生效的问题解决

    Java中logback 自动刷新不生效的问题解决

    本文主要介绍了Java中logback 自动刷新不生效的问题解决,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2023-05-05

最新评论