一起养成写作习惯!这是我参与「掘金日新计划 · 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 核心原理。