Spring Cloud Alibaba-Feign的源码分析

本文涉及的产品
全局流量管理 GTM,标准版 1个月
公共DNS(含HTTPDNS解析),每月1000万次HTTP解析
云解析 DNS,旗舰版 1个月
简介: Spring Cloud Alibaba-Feign的源码分析

一、源码分析

1、 源码推演


我们在想为什么我们调用接口StockFeignClient就能调用对应的服务呢?


StockFeignClient接口代码如下:


@FeignClient(name = "msb-stock")//,configuration = StockFeignConfiguration.class)
public interface StockFeignClient {
    /**
     * http://msb-stock/stock/reduce/{productId}
     * @param productId
     * @return
     */
    @GetMapping("/stock/reduce/{productId}")
    String reduce(@PathVariable Integer productId);
}
复制代码


StockFeignClient接⼝打个@FeignClient注解,它是怎么通过接⼝上的信息、找到接⼝的实现类的呢?我们看一下StockFeignClient发现⾥⾯就是⼀些SpringMVC相关的注解信息,⽐如接⼝类和⽅法上的@RequestMapping中、标注了具体访问时的路径以及请求⽅法(GET、PUT、POST、DELETE)是怎样的、@PathVariable标注了应该在请求路径上带上什么变量名、@RequestBody表示POST请求要带上的请求参数。


还有这个@FeignClient中name属性,这些信息一定是构建一个url, 好再@ReqeustMapping中我们知道我们的路径是/stock/reduce/{productId} 并且是一个get请求,


@GetMapping("/stock/reduce/{productId}")
    String reduce(@PathVariable Integer productId);
复制代码


那对应StockFeignClient上的注解@FeignClient注解,可以得到目标服务,也就是本次调用的服务msb-stock



@FeignClient(name = "msb-stock",configuration = StockFeignConfiguration.class)
复制代码


最终根据这些注解信息得到的请求URL信息为:/msb-stock//stock/reduce/12。


⽽⼜因为在SpringCloud体系内,发送⼀次请求都是通过HTTP协议来的,最终我们加上协议后,请求URL为: http://msb-stock//stock/reduce/45465。

分析到这⾥,我们再看下现在还缺什么:http://msb-stock/stock/reduce/45465,这个请求URL中⽬前唯⼀的疑点就在msb-stock上了,总不能就这么尴尬的写个msb-stock来发送请求吧,没有实际的ip和port怕是直接发起请求就报错了,所以肯定是需要将msb-stock解析成具体的ip和port,这样的URL才算是⼀个完整的URL、才能实际的发送有效请求出去。


并且我们是和nacos进行整合的,那么我们需要从nacos中获取所有服务对应的ip和port ,但是我们如果有多个实例那我们是不是需要利用负载均衡器来获取一个我们需要的服务,当然我们feign也整合了ribbon,所以我们底层可以使用ribbon进行负载均衡。



2、源码入口


源码分析的两种思路,一个是@EnableXXX 作为入口,另一个就是springboot的自动装配 xxxAutoConfiguration


image.png

进⼊到EnableFeignClients注解类中,会发现有个@Import注解,这个注解前面我们经常看到,这里导⼊了⼀个⽐较特别的类:FeignClietnsRegistrar,简单翻译下就是Feign的客户端注册器,注册器?这可能是吧@FeignClient注解标记的那些接口类,进行解析然后注入的


@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.TYPE})
@Documented
@Import({FeignClientsRegistrar.class})
public @interface EnableFeignClients {
    String[] value() default {};
    String[] basePackages() default {};
    Class<?>[] basePackageClasses() default {};
    Class<?>[] defaultConfiguration() default {};
    Class<?>[] clients() default {};
}
复制代码



3、扫描@FeignClient标注的类


因为他实现了ImportBeanDefinitionRegistrar 所以我们来看他的registerBeanDefinitions方法


public void registerBeanDefinitions(AnnotationMetadata metadata,
      BeanDefinitionRegistry registry) {
    // 解析默认的配置类EnableFeignClients
   registerDefaultConfiguration(metadata, registry);
    // 注册用@FeignClient标注的接口  
   registerFeignClients(metadata, registry);
}
复制代码


3.1 整体思路分析

image.png

image.png



3.2 获取扫描器


registerFeignClients⽅法⼀进去我们可以看到getScanner⽅法、很明显它就是获取⼀个扫描器,在getScanner⽅法中,发现它new了⼀个


ClassPathScanningCandidateComponentProvider类型的对象,⾥⾯有个⽅法isCandidateComponent,来判断是否是我们需要的


protected ClassPathScanningCandidateComponentProvider getScanner() {
   return new ClassPathScanningCandidateComponentProvider(false, this.environment) {
      @Override
      protected boolean isCandidateComponent(
            AnnotatedBeanDefinition beanDefinition) {
         boolean isCandidate = false;
         // 确定基础类是否独立,即它是一个顶级类或嵌套类(静态内部类)可以独立于封闭类构造。
         if (beanDefinition.getMetadata().isIndependent()) {
             // 判断是否是注解
            if (!beanDefinition.getMetadata().isAnnotation()) {
               isCandidate = true;
            }
         }
         return isCandidate;
      }
   };
}
复制代码


3.3 获取扫描包


image.png


3.4 获取标注@FeignClient的接口并注入容器


获取标注@FeignClient的接口

image.png

image.png


image.png

这里的扫描我们能想起mybatis的扫描。


注入容器


这里设计的类是FeignClientFactoryBean 他是一个FactoryBean 我们获取对象是调用getObject

image.png


总结:

1.以启动类上的@EnableFeignClients为⼊⼝,扫描启动类所在包路径以及该包下所有⼦包中的所有的类


2.从扫描到的类中、筛选出所有打了@FeignClient注解的类


3.解析@FeignClient注解中的属性,创建⼀个BeanDefinition并设置各种属性值,再注⼊到Spring容器中



相关文章
|
3月前
|
资源调度 Java 调度
Spring Cloud Alibaba 集成分布式定时任务调度功能
Spring Cloud Alibaba 发布了 Scheduling 任务调度模块 [#3732]提供了一套开源、轻量级、高可用的定时任务解决方案,帮助您快速开发微服务体系下的分布式定时任务。
14657 24
|
3月前
|
负载均衡 Java Spring
Spring cloud gateway 如何在路由时进行负载均衡
Spring cloud gateway 如何在路由时进行负载均衡
321 15
|
3月前
|
Java Spring
spring cloud gateway在使用 zookeeper 注册中心时,配置https 进行服务转发
spring cloud gateway在使用 zookeeper 注册中心时,配置https 进行服务转发
68 3
|
3月前
|
消息中间件 Java 开发者
Spring Cloud微服务框架:构建高可用、分布式系统的现代架构
Spring Cloud是一个开源的微服务框架,旨在帮助开发者快速构建在分布式系统环境中运行的服务。它提供了一系列工具,用于在分布式系统中配置、服务发现、断路器、智能路由、微代理、控制总线、一次性令牌、全局锁、领导选举、分布式会话、集群状态等领域的支持。
152 5
|
3月前
|
Java API 开发工具
Spring Boot与Spring Cloud Config的集成
Spring Boot与Spring Cloud Config的集成
|
3月前
|
消息中间件 Java Nacos
通用快照方案问题之通过Spring Cloud实现配置的自动更新如何解决
通用快照方案问题之通过Spring Cloud实现配置的自动更新如何解决
67 0
|
3月前
|
缓存 监控 Java
通用快照方案问题之Spring Boot Admin的定义如何解决
通用快照方案问题之Spring Boot Admin的定义如何解决
52 0
|
3月前
|
监控 NoSQL Java
通用快照方案问题之Martin Flower提出的微服务之间的通信如何解决
通用快照方案问题之Martin Flower提出的微服务之间的通信如何解决
39 0
|
3月前
|
Java 微服务 Spring
【spring cloud】注解@SpringCloudApplication和@SpringBootApplication的区别
【spring cloud】注解@SpringCloudApplication和@SpringBootApplication的区别
下一篇
无影云桌面