深入理解Spring Cloud系列#Feign详解

本文深入探讨了Spring Cloud Feign,解释了其作为服务间调用的简化工具,如何通过注解定义接口实现远程调用。文章详细介绍了Feign的实现原理,包括FeignClient的加载、请求模板的生成、JDK动态代理的应用,以及Feign的远程调用执行流程。此外,还讨论了Feign的关键技术点,如配置、容错处理和多参数传递策略,并提供了相关资源链接以供进一步学习。
摘要由CSDN通过智能技术生成

目录

什么是Feign

为什么需要Feign

Feign设计与原理

FeignClient的实现原理

Feigh 远程调用的执行流程

Feign关键技术点

Feign的Post和Get的多参数传递


什么是Feign

        Feign远程调用的思想是通过一系列的封装和处理,以JAVA注解@FeignClient的方式定义的远程调用API接口,最终转换成HTTP的请求形式,然后将HTTP的请求的响应结果,解码成JAVA Bean,返回给调用者。

        主程序入口添加了@EnableFeignClients注解开启对FeignClient扫描加载处理。根据Feign Client的开发规范,定义接口并加@FeignClientd注解。

        当程序启动时,会进行包扫描,扫描所有@FeignClients的注解的类,并且将这些信息注入Spring IOC容器中,当定义的的Feign接口中的方法被调用时,通过JDK的代理方式,来生成具体的RequestTemplate。当生成代理时,Feign会为每个接口方法创建一个RequestTemplate。当生成代理时,Feign会为每个接口方法创建一个RequestTemplate对象,该对象封装了HTTP请求需要的全部信息,如请求参数名,请求方法等信息都是在这个过程中确定的。

        然后RequestTemplate生成Request,然后把Request交给Client去处理,这里指的是Client可以是JDK原生的URLConnection,Apache的HttpClient,也可以是OKhttp,最后Client被封装到LoadBalanceClient类,这个类结合Ribbon负载均衡发起服务之间的调用。

为什么需要Feign

Feign设计与原理

JDK动态代理

 OldSystemPostFeign只是一个接口,Feign为什么需要使用接口来调用远程接口?原因就是使用JDK动态代理,我们可以去看Feign是如何进行处理。

  1. 遍历目标接口的所有方法
  2. 添加默认实现
  3. 创建动态代理处理器
  4. 进行代理
  • 我们已经知道Feign使用动态代理,这就是为什么我们只要接口封装远程接口就可以实现调用了,因为Feign给我们都每个调用接口创建了对应的代理类进行请求处理和响应处理。
//接口InvocationHandlerFactory的create的函数
/**
 * Controls reflective method dispatch.
 */
public interface InvocationHandlerFactory {

  InvocationHandler create(Target target, Map<Method, MethodHandler> dispatch);

  /**
   * Like {@link InvocationHandler#invoke(Object, java.lang.reflect.Method, Object[])}, except for a
   * single method.
   */
  interface MethodHandler {

    Object invoke(Object[] argv) throws Throwable;
  }

  static final class Default implements InvocationHandlerFactory {

    @Override
    public InvocationHandler create(Target target, Map<Method, MethodHandler> dispatch) {
      return new ReflectiveFeign.FeignInvocationHandler(target, dispatch);
    }
  }
}

//其实create函数返回是FeignInvocationHandler,它就是动态代理处理器
static class FeignInvocationHandler implements InvocationHandler {

    private final Target target;
    private final Map<Method, MethodHandler> dispatch;
    ...
    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
    ...
    return dispatch.get(method).invoke(args);
    }
    ...
}
  • 接下来,我们开始去找寻目标接口的每个方法的执行者,我们先要看接口的MethodHandler实现类:

    MethodHandler实现类

  • 默认实现类是SynchronousMethodHandler,当你看它的时候你就知道你找对了。
final class SynchronousMethodHandler implements MethodHandler {

  private static final long MAX_RESPONSE_BUFFER_SIZE = 8192L;

  private final MethodMetadata metadata;
  private final Target<?> target;
  private final Client client;
  private final Retryer retryer;
  private final List<RequestInterceptor> requestInterceptors;
  private final Logger logger;
  private final Logger.Level logLevel;
  private final RequestTemplate.Factory buildTemplateFromArgs;
  private final Options options;
  private final Decoder decoder;
  private final ErrorDecoder errorDecoder;
  private final boolean decode404;

  ...

  @Override
  public Object invoke(Object[] argv) throws Throwable {
    RequestTemplate template = buildTemplateFromArgs.create(argv);
    //feign的重试机制
    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;
      }
    }
  }

  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 {
        //HttpClient调用,返回response
      response = client.execute(request, options);
    } 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 (response.status() >= 200 && response.status() < 300) {
        if (void.class == metadata.returnType()) {
          return null;
        } else {
        //响应成功,进行解码
          return decode(response);
        }
      } else if (decode404 && response.status() == 404) {
      //响应失败,进行解码
        return decoder.decode(response, metadata.returnType());
      } else {
      //响应失败,使用异常解码器解码
        throw errorDecoder.decode(metadata.configKey(), response);
      }
    } catch (IOException e) {
      ...
  }
  ...
  Object decode(Response response) throws Throwable {
    try {
    //使用默认解码器解码,如果你设置了解码器,使用设置的进行解码
      return 
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值