SpringCloud源码解读之Feign(一)

Feign简介

  • Feign是一种声明式、模板化的HTTP客户端。声明式调用就像调用本地方法一样调用远程方法,无感知远程HTTP请求,让我们无需关注与远程的交互细节,更无需关注分布式环境开发。

  • 集成 Ribbon 和 Eureka 提供的负载均衡的客户端,支持断路器Hystrix,实现服务熔断和降级 。

基本使用

1.引入jar包
<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-openfeign</artifactId>
    <version>2.1.2.RELEASE</version>
</dependency>
2.启动类加注解EnableFeignClients
@SpringBootApplication
@ComponentScan(basePackages = {"com.example","com.mock"})
@EnableFeignClients(basePackages = {"com.example"})
public class DemoApplication {
    public static void main(String[] args) {
        SpringApplication.run(DemoApplication.class, args);
    }
}
3.定义接口及方法
@FeignClient(value = "userService")
public interface UserFeignClient {
    @RequestMapping("/user/id")
    String findById(String id);
}
4.业务中调用
@Resource
private UserFeignClient userFeignClient;
@Override
public String findUser(String id) {
    return userFeignClient.findById(id);
}

通过以上方式,让我们在微服务之间调用就如同调用本地方法一般,内部的HTTP远程调用细节全部封装在Feign客户端中。

源码解读

1.启动扫描过程

启动类注解EnableFeignClients引入FeignClientsRegistrar,这个类实现了ImportBeanDefinitionRegistrar接口,在IOC容器的启动过程中,会扫描到该接口是实现类并注册为bean definition,最终添加到容器中。

@Override
	public void registerBeanDefinitions(AnnotationMetadata metadata,
			BeanDefinitionRegistry registry) {
			// 注册默认的配置
		registerDefaultConfiguration(metadata, registry);
		// 为每一个添加了FeignClient的接口注册一个FeignClientFactoryBean
		registerFeignClients(metadata, registry);
	}

这个过程并没有实例化bean到容器中,只是先解析成BeanDefinition。default.com.example.demo.DemoApplication

第一步,registerDefaultConfiguration()方法:

private void registerDefaultConfiguration(AnnotationMetadata metadata,
      BeanDefinitionRegistry registry) {
      // 获取启动类EnableFeignClients注解的属性
   Map<String, Object> defaultAttrs = metadata
         .getAnnotationAttributes(EnableFeignClients.class.getName(), true);
	// 如果存在defaultConfiguration,则解析EnableFeignClients配置类
	// 然后构造beanName,为default+启动类的全限定名
   if (defaultAttrs != null && defaultAttrs.containsKey("defaultConfiguration")) {
      String name;
      if (metadata.hasEnclosingClass()) {
         name = "default." + metadata.getEnclosingClassName();
      }
      else {
         name = "default." + metadata.getClassName();
      }
      // 这里执行注册配置类到容器中(这个方法在下面其他地方还有用到)
      registerClientConfiguration(registry, name,
            defaultAttrs.get("defaultConfiguration"));
   }
}

registerClientConfiguration()方法:

private void registerClientConfiguration(BeanDefinitionRegistry registry, Object name,
      Object configuration) {
   BeanDefinitionBuilder builder = BeanDefinitionBuilder
         .genericBeanDefinition(FeignClientSpecification.class);
   // 添加name
   builder.addConstructorArgValue(name);
   // 添加指定的配置
   builder.addConstructorArgValue(configuration);
   registry.registerBeanDefinition(
         name + "." + FeignClientSpecification.class.getSimpleName(),
         builder.getBeanDefinition());
}

这里将EnableFeignClients上配置的defaultConfiguration属性值包装成一个FeignClientSpecification放到容器中。

我们来看FeignClientSpecification这个类的结构,name就是default,configuration就是我们defaultConfiguration属性指定的配置类。

class FeignClientSpecification implements NamedContextFactory.Specification {
   private String name;
   private Class<?>[] configuration;
 }

需要注意的是,这里是将我们配置的类包装进一个FeignClientSpecification对象中,即使我们在启动类注解上没有指定配置类,这里仍然会存在一个FeignClientSpecification,只是它的configuration为空而已。

注册默认配置的过程结束。

第二步,registerFeignClients()方法:

EnableFeignClients有几个属性是用来指定FeignClient的,registerFeignClients方法前面部分就是在解析获取需要扫描包的,这里不做细说。

String[] basePackages() default {};
Class<?>[] basePackageClasses() default {};
Class<?>[] clients() default {};

我们来看真正注册FeignClient的代码:

  • 解析每个客户端的配置
for (String basePackage : basePackages) {
   Set<BeanDefinition> candidateComponents = scanner
         .findCandidateComponents(basePackage);
   for (BeanDefinition candidateComponent : candidateComponents) {
      if (candidateComponent instanceof AnnotatedBeanDefinition) {
         // verify annotated class is an interface
         AnnotatedBeanDefinition beanDefinition = (AnnotatedBeanDefinition) candidateComponent;
         AnnotationMetadata annotationMetadata = beanDefinition.getMetadata();
         Assert.isTrue(annotationMetadata.isInterface(),
               "@FeignClient can only be specified on an interface");
		// 获取FeignClient注解的属性
         Map<String, Object> attributes = annotationMetadata
               .getAnnotationAttributes(
                     FeignClient.class.getCanonicalName());
		// 按照
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Spring Cloud是一组用于构建分布式系统的开框架,它为我们提供了一种轻量级的微服务架构的解决方案。而Dubbo是阿里巴巴开的高性能RPC框架,用于构建分布式服务框架。而Feign是Spring Cloud提供的一种声明式的Web服务客户端,它可以与Dubbo进行集成,提供更加便捷的服务调用方式。 在集成Dubbo和Feign之前,我们需要先将Dubbo注册到Spring Cloud的注册中心,使得Dubbo服务可以被Spring Cloud所管理。这样,我们就可以使用Feign作为Spring Cloud中的服务消费者来调用Dubbo提供的服务。通过Feign,我们可以避免编写繁琐的服务调用代码,只需要简单的声明式接口,并使用注解来定义具体的服务调用方法,Feign会动态生成代理实现类,自动处理服务调用的细节。 在使用Feign集成Dubbo时,我们需要在Spring Boot配置文件中进行相应的配置,声明需要调用的Dubbo服务接口。然后,通过在代码中定义Feign的接口,使用注解来标识调用的Dubbo服务地址、服务方法等。当我们调用该接口时,Feign会自动发起对Dubbo服务的远程调用。 通过将Feign与Dubbo集成,我们可以通过Spring Cloud的整体架构来统一管理和调用Dubbo的服务,简化了代码编写和服务调用的过程。同时,Feign还具有负载均衡、容错等一系列特性,可以进一步提高系统的稳定性和可靠性。 综上所述,通过集成Dubbo和Feign,我们可以更加方便地在Spring Cloud中调用和管理Dubbo的服务,提高系统的可维护性和可扩展性。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值