OpenFeign 架构原理(四):OpenFeign 的包扫描原理

997 阅读2分钟

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