OpenFeign 架构原理(五):注册 FeignClient 到 Spring 的原理

866 阅读2分钟

一起养成写作习惯!这是我参与「掘金日新计划 · 4 月更文挑战」的第3天,点击查看活动详情

上次我们深入讲解了 Ribbon 的架构原理,这次我们再来看下 Feign 远程调用的架构原理。

上次我们已经梳理了 OpenFeign 的包扫描原理,接着我们就来顺着这个核心流程来讲解 注册 FeignClient 到 Spring 的原理。

本文以开源 SpringCloud 项目 PassJava 作为示例。

开源地址: github.com/Jackson0714…

喜欢的小伙伴来点个 Star 吧,冲 2K Star。

注册 FeignClient 到 Spring 的原理

还是在 registerFeignClients 方法中,当 FeignClient 扫描完后,就要为这些 FeignClient 接口生成一个动态代理对象。

顺藤摸瓜,进到这个方法里面,可以看到这一段代码:

BeanDefinitionBuilder definition = BeanDefinitionBuilder
      .genericBeanDefinition(FeignClientFactoryBean.class);

核心就是 FeignClientFactoryBean 类,根据类的名字我们可以知道这是一个工厂类,用来创建 FeignClient Bean 的。

我们最开始用的 @FeignClient,里面有个参数 "passjava-study",这个其实注解的属性,当 OpenFeign 框架去创建 FeignClient Bean 的时候,就会使用这些参数去生成 Bean。流程图如下:

  • 解析 @FeignClient 定义的属性。
  • 将注解@FeignClient 的属性 + 接口 StudyTimeFeignService的信息构造成一个 StudyTimeFeignService 的 beanDefinition。
  • 然后将 beanDefinition 转换成一个 holder,这个 holder 就是包含了 beanDefinition, alias, beanName 信息。
  • 最后将这个 holder 注册到 Spring 容器中。

源码如下:

// 生成 beanDefinition
AbstractBeanDefinition beanDefinition = definition.getBeanDefinition();
// 转换成 holder,包含了 beanDefinition, alias, beanName 信息
BeanDefinitionHolder holder = new BeanDefinitionHolder(beanDefinition, className,
        new String[] { alias });
// 注册到 Spring 上下文中。
BeanDefinitionReaderUtils.registerBeanDefinition(holder, registry);

上面我们已经知道 FeignClient 的接口是如何注册到 Spring 容器中了。后面服务要调用接口的时候,就可以直接用 FeignClient 的接口方法了,如下所示:

@Autowired
private StudyTimeFeignService studyTimeFeignService;
​
// 省略部分代码
// 直接调用 
studyTimeFeignService.getMemberStudyTimeListTest(id);

但是我们并没有细讲这个 FeignClient 的创建细节,下面我们看下 FeignClient 的创建细节,这个也是 OpenFeign 核心原理。