springCloud实践之浅谈Feign原理


一、注册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
            .
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
### 回答1: Spring Cloud Feign是一个基于Netflix Feign的声明式Web服务客户端,它使得编写Web服务客户端变得更加简单。它通过注解的方式来定义和配置Web服务接口,使得开发者只需要关注业务逻辑的实现,而无需关注底层的实现细节。在运行时,Feign会根据注解信息自动创建出具体的Web服务客户端,并且将请求转发到指定的Web服务端点。同时,Feign还提供了负载均衡、熔断器等功能,可以帮助开发者构建高可用、高可靠的Web服务应用。 ### 回答2: Spring Cloud Feign是一个基于Spring Cloud的声明式REST客户端,可以让开发者更加便捷地进行微服务间的通信。其原理可以简单地概括为:通过注解定义服务接口,Feign根据注解生成服务代理对象,调用服务时候,Feign将请求参数编码成HTTP请求并发送请求到服务提供方,接收到服务提供方的响应后,将响应解码成返回对象并返回给调用方。 在实现原理上,Spring Cloud Feign主要依赖于以下三种技术: 1.动态代理技术:Feign使用Java动态代理技术,在运行时生成服务接口的实现类,并将服务接口方法映射到HTTP请求中,实现了将服务接口映射到HTTP请求的自动化。 2.Ribbon和Eureka或Consul:Feign利用Ribbon和Eureka或Consul两个组件实现了负载均衡和服务发现。在服务消费方和服务提供方之间建立连接时,使用Ribbon对服务提供方进行负载均衡,加上Eureka或Consul的服务发现机制,使得分布式系统之间的通信变得更加稳定和可靠。 3.编解码技术:Feign使用编解码技术将请求参数和响应抽象为Java对象,并使用Jackson实现JSON序列化和反序列化,实现了请求参数的传输和响应结果的解析。 总之,Spring Cloud Feign使得微服务之间的通信更加便捷、高效、可靠,为微服务架构的开发提供了有效的解决方案。 ### 回答3: Spring Cloud Feign是一种基于Spring Cloud的轻量级原型客户端,它使用了注解的方式来定义和实现RESTful服务的客户端,并且不需要额外的代码来实现远程调用,只需要使用接口来定义相应的服务,Feign会自动帮我们实现相应的调用请求。 Spring Cloud Feign的实现原理包括以下几个方面: 1. 接口代理 在使用Spring Cloud Feign时,我们只需要定义一个接口,然后在接口上添加相应的注解,就可以轻松地实现远程服务的调用。这是因为在使用Feign时,Feign会根据接口定义生成一个代理对象,在运行时使用代理对象来调用远程服务。 2.注解解析器 Spring Cloud Feign主要通过注解的方式来定义RESTful服务,它会解析这些注解来生成相应的HTTP请求。通过使用注解,我们可以定义URL、HTTP请求方法、请求头信息、请求参数等,灵活地满足我们对于远程服务的调用需求。 3.集成了Ribbon负载均衡 Spring Cloud Feign在进行远程调用时,还会集成Ribbon负载均衡机制。Ribbon是Netflix开源的一款负载均衡框架,它通过在客户端侧配置算法来均衡负载,可以使得服务调用更加稳定和高效。 4.优秀的可扩展性 Spring Cloud Feign提供了出色的可扩展性,我们可以通过自定义注解解析器来扩展Feign的功能。同时,Feign还支持自定义编码器、解码器、日志记录器等,可以支持更复杂、更个性化的远程服务调用需求。 总之,Spring Cloud Feign是一种优秀的远程服务调用工具,它使用注解来定义RESTful服务并自动生成代理对象实现调用,同时还集成了Ribbon负载均衡机制,可扩展性强,非常适合用于微服务架构下的远程服务调用。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值