springCloud实践之浅谈Feign原理

本文详细探讨了Spring Cloud Feign的实现过程,包括启用@EnableFeignClients注解,注册Bean配置,实例化FeignContext,构造FeignBuilder,以及生成负载均衡代理类。在生成代理类的过程中,涉及了Targeter的选择,如DefaultTargeter和HystrixTargeter,并解释了如何根据配置创建MethodHandler来处理请求。
摘要由CSDN通过智能技术生成


一、注册FeignClient配置类和FeignClient BeanDefinition

1.@EnableFeignClients注解

先来看一下启动类上@EnableFeignClients注解,跟进直接看下都做了些什么:

class FeignClientsRegistrar implements ImportBeanDefinitionRegistrar,
      ResourceLoaderAware, EnvironmentAware {
   

   // patterned after Spring Integration IntegrationComponentScanRegistrar
   // and RibbonClientsConfigurationRegistgrar

   private ResourceLoader resourceLoader;

   private Environment environment;

   public FeignClientsRegistrar() {
   
   }

   @Override
   public void setResourceLoader(ResourceLoader resourceLoader) {
   
      this.resourceLoader = resourceLoader;
   }

   @Override
   public void registerBeanDefinitions(AnnotationMetadata metadata,
         BeanDefinitionRegistry registry) {
   
	  //注册默认配置
      registerDefaultConfiguration(metadata, registry);
	  //注册所有FeignClent beanDeifintion
      registerFeignClients(metadata, registry);
   }

2.注册bean配置的两个方法

分别来看一下上面两个方法:注册默认配置方法registerDefaultConfiguration

private void registerDefaultConfiguration(AnnotationMetadata metadata,
      BeanDefinitionRegistry registry) {
   
   //获取EnableFeignClients注解里面所有属性key和value
   Map<String, Object> defaultAttrs = metadata
         .getAnnotationAttributes(EnableFeignClients.class.getName(), true);

   if (defaultAttrs != null && defaultAttrs.containsKey("defaultConfiguration")) {
   
      String name;
	  //判断是否存在内部类,例如default.xxx.TestApplication
      if (metadata.hasEnclosingClass()) {
   
   		 //针对注解元数据metadate对应一个内部类或者方法返回的方法本地类的情形
         name = "default." + metadata.getEnclosingClassName();
      }
      else {
   
         name = "default." + metadata.getClassName();
      }
	  //name 默认以default开头,之后会根据名称选择配置
      registerClientConfiguration(registry, name,
            defaultAttrs.get("defaultConfiguration"));
   }
}
registerDefaultConfiguration方法是读取启动类上面@EnableFeignClients注解中声明Feign相关配置类,默认name为Default,一般情况下不无需配置。用默认的feignAutoConfiguration即可。有一个比较重要的方法:注册配置registerClientConfiguration,启动流程中一共有两处读取了feign配置类,这里是第一处,先来看一下方法:
private void registerClientConfiguration(BeanDefinitionRegistry registry, Object name,
      Object configuration) {
   
   //定义FeignClientSpecification的Definition构建器
   BeanDefinitionBuilder builder = BeanDefinitionBuilder
         .genericBeanDefinition(FeignClientSpecification.class);
   builder.addConstructorArgValue(name);
   builder.addConstructorArgValue(configuration);
   //注册bean,(会存在多个FeignClientSpecification但key不同)
   registry.registerBeanDefinition(
         name + "." + FeignClientSpecification.class.getSimpleName(),
         builder.getBeanDefinition());
}
将bean配置类包装成FeignClientSpecification,注入到容器中。这个对象非常重要,其中包含了FeignClient需要的重试策略、超时策略、日志等配置,如果某个服务没有配置,则读取默认配置。
扫描FeignClient registerFeignClients方法主要扫描类路径,对所有的FeignClient生成对应的BeanDefinItion
public void registerFeignClients(AnnotationMetadata metadata,
      BeanDefinitionRegistry registry) {
   
	//初始化扫描器
   ClassPathScanningCandidateComponentProvider scanner = getScanner();
   scanner.setResourceLoader(this.resourceLoader);

   Set<String> basePackages;
	//获取EnableFeignClients注解里面的所有属性key和Value
   Map<String, Object> attrs = metadata
         .getAnnotationAttributes(EnableFeignClients.class.getName());
	//定义扫描器的过滤规则(只获取FeignClient注解修饰的类)
   AnnotationTypeFilter annotationTypeFilter = new AnnotationTypeFilter(
         FeignClient.class);
   final Class<?>[] clients = attrs == null ? null
         : (Class<?>[]) attrs.get("clients");
	//是否制定clients属性
   if (clients == null || clients.length == 0) {
   
      scanner.addIncludeFilter(annotationTypeFilter);
      basePackages = getBasePackages(metadata);
   }
   else {
   
      final Set<String> clientClasses = new HashSet<>();
      basePackages = new HashSet<>();
      for (Class<?> clazz : clients) {
   
		 //获取类的包名
         basePackages.add(ClassUtils.getPackageName(clazz));
		 //获取权限类名
         clientClasses.add(clazz.getCanonicalName());
      }
      AbstractClassTestingTypeFilter filter = new AbstractClassTestingTypeFilter() {
   
         @Override
         protected boolean match(ClassMetadata metadata) {
   
            String cleaned = metadata.getClassName().replaceAll("\\$", ".");
            return clientClasses.contains(cleaned);
         }
      };
	  //扫描器定义两个过滤规则
      scanner.addIncludeFilter(
            new AllTypeFilter(Arrays.asList(filter, annotationTypeFilter)));
   }
    //获取扫描目录下面所有的bean BeanDefinition
   for (String basePackage : basePackages) {
   
      Set<BeanDefinition> candidateComponents = scanner
            .findCandidateComponents(basePackage);
      for (BeanDefinition candidateComponent : candidateComponents) {
   
         if (candidateComponent instanceof AnnotatedBeanDefinition) {
   
            
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值