Spring Cloud OpenFeign 实现原理解析

本文介绍了Spring Cloud OpenFeign的基础知识和实现原理,包括Feign的基本概念、Spring Cloud OpenFeign的作用、Feign的初始化构造器、代理对象生成、接口方法解析以及HTTP请求的处理。重点解析了FeignClient接口的解析过程,涉及到Contract和MethodHandler,并讨论了Spring Cloud中OpenFeign的启用和Bean注册。
摘要由CSDN通过智能技术生成

1、什么是Feign

Feign 是一个声明式 HTTP 调用客户端,Feign 的目标是使编写Java HTTP客户端更加容易。Feign 的声明编程调用思想来自 Retrofit ,Retrofit 在 Android 端十分流行,Feign 借鉴了 Retrofit 的编程理念。

Feign 支持以下几种 HTTP 客户端 Apache Httpclient , Square OkHttp , HttpURLConnection。

2、什么是 Spring Cloud OpenFeign

Spring Cloud 中服务与服务之间的调用都是通过 HTTP 完成的,而 Spring Cloud OpenFeign 就是基于 Fegin 的封装,与Spring Boot 结合实现开箱即用,来实现服务之间内部调用的客户端。

3、Feign 实现原理

以Fegin官方提供的示例(https://github.com/OpenFeign/feign),来解析其实现的原理。如下,获取指定 Github 仓库的所有贡献者:

 /**
     * 定义声明式接口
     */
    interface GitHub {
        /**
         * 声明调用方式 GET 和 调用地址,获取指定仓库贡献者列表
         */
        @RequestLine("GET /repos/{owner}/{repo}/contributors")
        List<Contributor> contributors(@Param("owner") String owner, @Param("repo") String repository);

        class Contributor {
            String login;
            int contributions;
        }
    }

    public static void main(String[] args) {
        //Feign客户端初始化
        GitHub github = Feign.builder()
                .decoder(new GsonDecoder())
                .logLevel(Logger.Level.FULL)
                .target(GitHub.class, "https://api.github.com");
        //获取并打印feign的贡献者列表。
        List<GitHub.Contributor> contributors = github.contributors("OpenFeign", "feign");
        contributors.forEach(contributor -> System.out.println(contributor.login + " (" + contributor.contributions + ")"));
    }

从示例中可以看到,Feign客户端初始化包括三个部分,Feign 默认配置初始化、设置自定义配置、生成代理对象。

在这里插入图片描述

3.1、Feign.builder() 初始化构造器

根据默认值初始化 Feign 构造器

public static Builder builder() {
    return new Builder();
  }

public static class Builder {

    //请求拦截器,拦截每一个请求,添加或修改请求属性
    private final List<RequestInterceptor> requestInterceptors =
        new ArrayList<RequestInterceptor>();
    //日志级别,默认关闭
    private Logger.Level logLevel = Logger.Level.NONE;
    //定义接口上有效的注释和值。
    private Contract contract = new Contract.Default();
    //客户端实例化。空参数表示使用默认值。
    private Client client = new Client.Default(null, null);
    //默认重试规则
    private Retryer retryer = new Retryer.Default();
    private Logger logger = new NoOpLogger();
    //编码器
    private Encoder encoder = new Encoder.Default();
    //解码器
    private Decoder decoder = new Decoder.Default();
    //生成查询参数,eg: "/uri?name={name}&number={number}"
    private QueryMapEncoder queryMapEncoder = new FieldQueryMapEncoder();
    //错误解码处理器
    private ErrorDecoder errorDecoder = new ErrorDecoder.Default();
    //控制请求的参数,比如:超时时间
    private Options options = new Options();
    //反射控制工厂
    private InvocationHandlerFactory invocationHandlerFactory =
        new InvocationHandlerFactory.Default();
    private boolean decode404;
    private boolean closeAfterDecode = true;
    private ExceptionPropagationPolicy propagationPolicy = NONE;

    。。。。。。省略。。。。。。。。
}

3.2、Feign.target() 生成代理对象

 public <T> T target(Class<T> apiType, String url) {
      return target(new HardCodedTarget<T>(apiType, url));
    }

    public <T> T target(Target<T> target) {
      //调用JDK动态代理生成接口代理类
      return build().newInstance(target);
    }

    public Feign build() {
      SynchronousMethodHandler.Factory synchronousMethodHandlerFactory =
          new SynchronousMethodHandler.Factory(client, retryer, requestInterceptors, logger,
              logLevel, decode404, closeAfterDecode, propagationPolicy);
      ParseHandlersByName handlersByName =
          new ParseHandlersByName(contract, options, encoder, decoder, queryMapEncoder,
              errorDecoder, synchronousMethodHandlerFactory);
     // 注入依赖配置项
      return new ReflectiveFeign(handlersByName, invocationHandlerFactory, queryMapEncoder);
    }
    
    public class ReflectiveFeign extends Feign {
      @Override
      public <T> T newInstance(Target<T> target) {
       //根据 Contract 约定,解析接口方法上的注解,建立方法名与对应处理器的映射关系
        Map<String, MethodHandler> nameToHandler = targetToHandlersByName.apply(target);
        //收集方法对象与对应方法处理器的映射关系
        Map<Method, MethodHandler> methodToHandler = new LinkedHashMap<Method, MethodHandler>();
        //收集默认方法处理器
        List<DefaultMethodHandler> defaultMethodHandlers = new LinkedList<DefaultMethodHandler>();
    
        for (Method method : target.type().getMethods()) {
          if (method.getDeclaringClass() == Object.class) {
            continue;
          } else if (Util.isDefault(method)) {
            DefaultMethodHandler handler = new DefaultMethodHandler(method);
            defaultMethodHandlers.add(handler);
            methodToHandler.put(method, handler);
          } else {
            methodToHandler.put(method, nameToHandler.get(Feign.configKey(target.type(), method)));
          }
        }
        // 使用JDK动态代理为接口生成代理对象,实际业务处理交给 InvocationHandler 处理,实质就是调用相应
  • 0
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值