一起养成写作习惯!这是我参与「掘金日新计划 · 4 月更文挑战」的第3天,点击查看活动详情。
上次我们深入讲解了 Ribbon 的架构原理,这次我们再来看下 Feign 远程调用的架构原理。
上次我们已经梳理了 OpenFeign 的核心流程,接着我们就来顺着这个核心流程来讲解 OpenFeign 包扫描原理。
本文以开源 SpringCloud 项目 PassJava 作为示例。
开源地址: github.com/Jackson0714…
喜欢的小伙伴来点个 Star 吧,冲 2K Star。
OpeFeign 包扫描原理
上面的 PassJava 示例代码中,涉及到了一个 OpenFeign 的注解:@EnableFeignClients。根据字面意思可以知道,可以注解是开启 OpenFeign 功能的。
包扫描的基本流程如下:
(1)@EnableFeignClients 这个注解使用 Spring 框架的 Import 注解导入了 FeignClientsRegistrar 类,开始了 OpenFeign 组件的加载。PassJava 示例代码如下所示。
// 启动类加上这个注解
@EnableFeignClients(basePackages = "com.jackson0714.passjava.member.feign")
// EnableFeignClients 类还引入了 FeignClientsRegistrar 类
@Import(FeignClientsRegistrar.class)
public @interface EnableFeignClients {
...
}
(2)FeignClientsRegistrar 负责 Feign 接口的加载。
源码如下所示:
@Override
public void registerBeanDefinitions(AnnotationMetadata metadata,
BeanDefinitionRegistry registry) {
// 注册配置
registerDefaultConfiguration(metadata, registry);
// 注册 FeignClient
registerFeignClients(metadata, registry);
}
(3)registerFeignClients 会扫描指定包。
核心源码如下,调用 find 方法来查找指定路径 basePackage 的所有带有 @FeignClients 注解的带有 @FeignClient 注解的类、接口。
Set<BeanDefinition> candidateComponents = scanner
.findCandidateComponents(basePackage);
(4)只保留带有 @FeignClient 的接口。
// 判断是否是带有注解的 Bean。
if (candidateComponent instanceof AnnotatedBeanDefinition) {
// 判断是否是接口
AnnotatedBeanDefinition beanDefinition = (AnnotatedBeanDefinition) candidateComponent;
AnnotationMetadata annotationMetadata = beanDefinition.getMetadata();
// @FeignClient 只能指定在接口上。
Assert.isTrue(annotationMetadata.isInterface(),
"@FeignClient can only be specified on an interface");
接下来我们再来看这些扫描到的接口是如何注册到 Spring 中。
作者简介:悟空,8年一线互联网开发和架构经验,用故事讲解分布式、架构设计、Java 核心技术。《JVM性能优化实战》专栏作者,开源了《Spring Cloud 实战 PassJava》项目,公众号:悟空聊架构。本文已收录至 www.passjava.cn