从一个简单案例说起

主启动类

  1. @SpringBootApplication
  2. @EnableDiscoveryClient
  3. @EnableFeignClients
  4. public class OrderFeignMain80 {
  5. public static void main(String[] args) {
  6. SpringApplication.run(OrderFeignMain80.class, args);
  7. }
  8. }

业务Service (在FeignClient上写要调用的微服务名称)

  1. @FeignClient(name = "cloud-payment-service")
  2. public interface PaymentFeignService {
  3. @GetMapping("/payment/get/{id}")
  4. CommonResult<Payment> getPaymentById(@PathVariable("id") Long id);
  5. }

从上述的简单案例中,看出,只需要在主启动类上添加@EnableFeignClients,再声明一个接口,即可完成远程调用,那么,关键就在于@EnableFeignClients

所以,就看看@EnableFeignClients 干了什么?

  1. @Retention(RetentionPolicy.RUNTIME)
  2. @Target(ElementType.TYPE)
  3. @Documented
  4. @Import(FeignClientsRegistrar.class)
  5. public @interface EnableFeignClients {
  6. }

通过上面的源码可以看出,@EnableFeignClients 通过@Import导入了一个组件,所以,又转向了FeignClientsRegistrar,可以看出,FeignClientsRegistrar实现了ImportBeanDefinitionRegistrar

  1. class FeignClientsRegistrar
  2. implements ImportBeanDefinitionRegistrar, ResourceLoaderAware, EnvironmentAware{
  3. }

那么,就可以在 registerBeanDefinitions 导入一些组件,在 FeignClientsRegistrar 中干了以下两件事

  1. @Override
  2. public void registerBeanDefinitions(AnnotationMetadata metadata,
  3. BeanDefinitionRegistry registry) {
  4. registerDefaultConfiguration(metadata, registry);
  5. registerFeignClients(metadata, registry);
  6. }
  1. registerDefaultConfiguration(metadata, registry);

注册默认的配置(defaultConfiguration),这边没有写,跳过

  1. registerFeignClients(metadata, registry); 注册Feign的客户端,主要分为如下几步:

    1. getScanner(); 获取扫描器

      1. # 这里重写了 判断组件是否扫描的方法
      2. return new ClassPathScanningCandidateComponentProvider(false, this.environment) {
      3. @Override
      4. protected boolean isCandidateComponent(
      5. AnnotatedBeanDefinition beanDefinition) {
      6. boolean isCandidate = false;
      7. if (beanDefinition.getMetadata().isIndependent()) {
      8. if (!beanDefinition.getMetadata().isAnnotation()) {
      9. isCandidate = true;
      10. }
      11. }
      12. return isCandidate;
      13. }
      14. };
    2. scanner.setResourceLoader(this.resourceLoader) 设置资源的加载器

    3. scanner.findCandidateComponents(basePackage) 调用扫描器,扫描所有的 FeignClient
    4. registerFeignClient(registry, annotationMetadata, attributes) 将FeignClient 注册到容器中
      1. BeanDefinitionBuilder.genericBeanDefinition(FeignClientFactoryBean.class) 生成 FeignClientFactoryBean 的bean定义,将Feign的接口类型,转成了 FeignClientFactoryBean类型

那么,在真正执行远程调用的时候,将会调用 FeignClientFactoryBean 的getObject() 获取Feign接口的代理对象

  1. @Override
  2. public Object getObject() throws Exception {
  3. return getTarget();
  4. }

getTarget() 中的方法如下

  1. this.applicationContext.getBean(FeignContext.class); 第一步,从容器中获取 FeignContext对象

    1. # FeignContext 是在 自动注入中 FeignAutoConfiguration 中加入到容器中的
    2. @Bean
    3. public FeignContext feignContext() {
    4. FeignContext context = new FeignContext();
    5. context.setConfigurations(this.configurations);
    6. return context;
    7. }
  2. feign(context); 将FeignContext 转化为 Feign.Builder

  3. loadBalance(builder, context,new HardCodedTarget<>(this.type, this.name, this.url));

    1. getOptional(context, Client.class); 将会从容器中取得Client类型 的 LoadBalancerFeignClient 实例,原因如下:
      1. # 自动注入中导入的 DefaultFeignLoadBalancedConfiguration
      2. @Import({ HttpClientFeignLoadBalancedConfiguration.class,
      3. OkHttpFeignLoadBalancedConfiguration.class,
      4. DefaultFeignLoadBalancedConfiguration.class })
      5. public class FeignRibbonClientAutoConfiguration {}
      6. # DefaultFeignLoadBalancedConfiguration
      7. @Bean
      8. @ConditionalOnMissingBean
      9. public Client feignClient(CachingSpringLoadBalancerFactory cachingFactory,
      10. SpringClientFactory clientFactory) {
      11. return new LoadBalancerFeignClient(new Client.Default(null, null), cachingFactory,
      12. clientFactory);
      13. }
  4. targeter.target(this, builder, context, new HardCodedTarget<>(this.type, this.name, url)) 调用Targeter对象的target方法,生成代理对象

    1. 将会调用的是DefaultTargeter,其代码为:

      1. # DefaultTargeter#target()
      2. feign.target(target);
      3. # 调用feigntarget方法
      4. # feign#target()
      5. public <T> T target(Target<T> target) {
      6. return this.build().newInstance(target);
      7. }
      8. # 其调用build(),生成一个Feign的实例,最终生成的是 ReflectiveFeign
      9. public Feign build() {
      10. Factory synchronousMethodHandlerFactory = new Factory(this.client, this.retryer, this.requestInterceptors, this.logger, this.logLevel, this.decode404, this.closeAfterDecode, this.propagationPolicy);
      11. ParseHandlersByName handlersByName = new ParseHandlersByName(this.contract, this.options, this.encoder, this.decoder, this.queryMapEncoder, this.errorDecoder, synchronousMethodHandlerFactory);
      12. return new ReflectiveFeign(handlersByName, this.invocationHandlerFactory, this.queryMapEncoder);
      13. }
    2. 在 newInstance中,往目标方法中,注入了一个 InvocationHandler,其真实类型是FeignInvocationHandler,将会在目标方法执行的时候,进行拦截,执行其对应的invoke方法

当通过Feign请求其他微服务时,将会首先调用 FeignInvocationHandler 的invoke方法

最终会调用LoadBalancerFeignClient#execute()

最后通过RibbonRequest去实现的负载均衡