OpenFeign

OpenFeign是一个声明式RESTful网络请求客户端。OpenFeign会根据带有注解的函数信息构建出网络请求的模板,在发送网络请求之前,OpenFeign会将函数的参数值设置到这些请求模板中。虽然OpenFeign只能支持基于文本的网络请求,但是可以极大简化网络请求的实现,方便快速构建自己的网络请求应用。

OpenFeign的Spring应用架构一般分为三部分,分别为注册中心,服务提供者和服务消费者。服务提供者向服务注册中心注册自己,然后服务消费者通过OpenFeign发送请求时,OpenFeign会向服务注册中心获取关于服务提供者的信息,然后再向服务提供者发送网络请求。

消费者添加@EnableFeignClients开启Spring Cloud OpenFeign 的自动化配置功能

@EnableFeignClients就像一个开关,只有使用了该注解,OpenFeign相关的组件和配置机制才会生效。

源码分析

FeignClientFactoryBean是创建@FeignClient修饰的接口类Bean实例的工厂类,FeignContext是配置组件的上下文环境,保存着相关组件的不同实例,这些实例由不同的FeignConfiguration配置构造出来,SynchronousMethodHandler是MethodHandler的子类,可以在FeignClient相应方法被调用时发送网络请求,然后再将请求响应转化为函数返回值进行输出。

OpenFeign会首先进行相关BeanDefinition的动态注册,然后当Spring容器注入相关实例时会进行实例的初始化,最后当FeignClient接口实例的函数被调用时会发送网络请求。

动态注入BeanDefinition

@EnableFeignClients三个作用:

  1. 引入FeignClientsRegistrar
  2. 指定FeignClient的包信息,也就是指定FeignClient接口类所在的包名
  3. 指定FeignClient接口类的自定义配置类
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
@Documented
@Import(FeignClientsRegistrar.class)
public @interface EnableFeignClients {

   /**
    * Alias for the {@link #basePackages()} attribute. Allows for more concise annotation
    * declarations e.g.: {@code @ComponentScan("org.my.pkg")} instead of
    * {@code @ComponentScan(basePackages="org.my.pkg")}.
    * @return the array of 'basePackages'.
    */
   String[] value() default {};

   /**
    * Base packages to scan for annotated components.
    * <p>
    * {@link #value()} is an alias for (and mutually exclusive with) this attribute.
    * <p>
    * Use {@link #basePackageClasses()} for a type-safe alternative to String-based
    * package names.
    * @return the array of 'basePackages'.
    */
   String[] basePackages() default {};

   /**
    * Type-safe alternative to {@link #basePackages()} for specifying the packages to
    * scan for annotated components. The package of each class specified will be scanned.
    * <p>
    * Consider creating a special no-op marker class or interface in each package that
    * serves no purpose other than being referenced by this attribute.
    * @return the array of 'basePackageClasses'.
    */
   Class<?>[] basePackageClasses() default {};

   /**
    * A custom <code>@Configuration</code> for all feign clients. Can contain override
    * <code>@Bean</code> definition for the pieces that make up the client, for instance
    * {@link feign.codec.Decoder}, {@link feign.codec.Encoder}, {@link feign.Contract}.
    *
    * @see FeignClientsConfiguration for the defaults
    * @return list of default configurations* A custom <code>@Configuration</code> for all feign clients. Can contain override
    * <code>@Bean</code> definition for the pieces that make up the client, for instance
    * {@link feign.codec.Decoder}, {@link feign.codec.Encoder}, {@link feign.Contract}.
    *
    * @see FeignClientsConfiguration for the defaults
    * @return list of default configurations
    */
   Class<?>[] defaultConfiguration() default {};

   /**
    * List of classes annotated with @FeignClient. If not empty, disables classpath
    * scanning.
    * @return list of FeignClient classes
    */
   Class<?>[] clients() default {};

}

FeignClientsRegistrar是ImportBeanDefinitionRegistrar的子类,Spring用ImportBeanDefinitionRegistrar来动态注册BeanDefinition。OpenFeign通过FeignClientsRegistrar来处理@FeignClient修饰的FeignClient接口类,将这些接口类的BeanDefinition注册到Spring容器中,这样就可以使用@Autowried等方式自动装载这些FeignClient接口类的Bean实例。