Feign底层原理分析-自动装载&动态代理

1、什么是Feign?

这里套用Feign官方Github上的介绍:“Feign是一个灵感来自于Retrofit、JAXRS-2.0、WebSocket的Java Http客户端,Feign的主要目标是降低大家使用Http API的复杂性”。

其实,Feign底层依赖于Java的动态代理机制,对原生Java Socket或者Apache HttpClient进行封装,实现了基于Http协议的远程过程调用。当然,Feign还在此基础上实现了负载均衡、熔断等机制。

2、为什么要使用Feign?

  • 声明式Http Client相对于编程式Http Client代码逻辑更加简洁,不需要处理复杂的编码请求和响应,只需要像调用本地方法即可,提高编码效率

  • 集中管理Http请求方法,代码边界更加清晰

  • 更好的集成负载均衡、熔断降级等功能

3、Feign依赖注入原理

使用过Feign的同学都知道,@EnableFeignClients注解是开启Fiegn功能的关键,我们通常会在该注解中添加FeignClient的所在包,以便Spring容器能够扫描到所有的FeignClient,并进行托管。后面我们便可以使用@Autowired注解自动导入了。

@SpringBootApplication @EnableFeignClients(basePackages = {"com.**.feign"}) public class Application {} 复制代码

该注解样式也是很多第三方包集成Springboot所使用的套路:一般都是开启该注解后,Springboot便可以自动装载第三方包所指定的Class,我们便可以直接使用第三方包所提供的功能,非常方便。

接下来不会详细介绍自动装载的部分,而是直接给出自动装载的主脉络,看看Spring容器到底装载了什么bean。

3.1、Feign自动装载

首先进入@EnableFeignClients源码中,查看该注解导入了什么Registrar注册器,这个注册器便是自动装载的关键。

@Retention(RetentionPolicy.RUNTIME) @Target(ElementType.TYPE) @Documented @Import(FeignClientsRegistrar.class) public @interface EnableFeignClients {...} 复制代码

从源码中可以看出,@EnableFeignClients 注解导入的是自定义的FeignClientsRegistrar类。

这种类型的注册器一般会继承Spring中的 ImportBeanDefinitionRegistrar接口,并在registerBeanDefinitions实现方法中向Spring容器注册一些bean,以达到自动注入第三方功能的目的。

// [1] 继承ResourceLoaderAware和EnvironmentAware class FeignClientsRegistrar implements ImportBeanDefinitionRegistrar, ResourceLoaderAware, EnvironmentAware { @Override public void registerBeanDefinitions(AnnotationMetadata metadata, BeanDefinitionRegistry registry) { // [2] 注册默认的Feign配置 registerDefaultConfiguration(metadata, registry); // [3] 注册所有定义的FeignClient registerFeignClients(metadata, registry); } }
  • [1] 从类的定义中,我们可以发现还实现了ResourceLoaderAware、EnvironmentAware两个Spring钩子接口,那么该注册类必然持有资源加载器和Spring的环境变量等信息,这个不过多叙述。

  • [2] 该方法会从@EnableFeignClients注解中提取defaultConfiguration这个key和对应的value,并把它当作默认的Feign配置注册到Spring容器中。如果没有该key,则不做任何处理。

  • [3] registerFeignClients方法会扫描@EnableFeignClients注解的basePackages,注册所有的FeignClient,下面详细介绍。

public void registerFeignClients(AnnotationMetadata metadata, BeanDefinitionRegistry registry) { LinkedHashSet<BeanDefinition> candidateComponents = new LinkedHashSet<>(); Map<String, Object> attrs = metadata.getAnnotationAttributes(EnableFeignClients.class.getName()); // [1] 获取clients属性 final Class<?>[] clients = attrs == null ? null : (Class<?>[]) attrs.get("clients"); if (clients == null || clients.length == 0) { // [2] 如果clients属性为null,则获取basePackages属性,扫描其中的所有client ClassPathScanningCandidateComponentProvider scanner = getScanner(); scanner.setResourceLoader(this.resourceLoader); scanner.addIncludeFilter(new AnnotationTypeFilter(FeignClient.class)); Set<String> basePackages = getBasePackages(metadata); for (String basePackage : basePackages) { candidateComponents.addAll(scanner.findCandidateComponents(basePackage)); } } else { // [3] 如果clients属性不为null,则直接注入 for (Class<?> clazz : clients) { candidateComponents.add(new AnnotatedGenericBeanDefinition(clazz)); } } // [4] 遍历所有的clients,将其封装为BeanDefinition注册进Spring容器中 for (BeanDefinition candidateComponent : candidateComponents) { if (candidateComponent instanceof AnnotatedBeanDefinition) { // ve
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值