Spring Cloud 远程调用核心组件介绍

核心组件与概念

读者在阅读Feign源码时,可以沿着两条路线进行,一是FeignServiceClient这样的被@FeignClient修饰的接口类如何被创建出来,也就是其Bean对象是如何被构建的,二是调用FeignServiceClient对象的响应方法时,Feign是如何发送网络请求的。而Feign相关的类也可以以此来进行分类,一部分是用来初始化相应的Bean示例的,一部分是用来在调用方法时发送网络请求的。
image.png

Feign关键类的类图

上图是Feign相关的关键类图,其中比较重要的类为FeignClientFactoryBean,FeignContext,SynchronousMethodHandler。其中FeignClientFactoryBean可以创建@FeignClient修饰的接口类Bean示例;FeignContext作为配置的上下文环境,保存着相关组件的不同实例,这些示例都是按照不同的FeignConfiguration所构造出来的;SynchronousMethodHandlerMethodHandler的子类,可以在相应方法被调用时发送网络请求,然后再将请求响应转化为函数返回值进行输出。
image.png

源码流程图

图是后续源码讲解的流程图,Feign会首先进行相关BeanDefinition的动态注册,然后当spring容器注入相关实例时会进行实例的初始化,最后当相关实例的函数被调用时会进行发送网络请求。

动态注册BeanDefinition

Feign可以通过多种方式进行自定义配置,配置的变化会导致接口类初始化时使用不同的实现类,从而控制Feign的相关行为,比如说网络请求的编解码,压缩和日志处理。可以说,了解Feign配置和实例初始化的流程和原理对于我们学习和使用Feign有着至关重要的作用,而且Spring Cloud的所有项目的配置和实例初始化过程原理基本相同,了解了Feign的原理,就可以触类旁通,一通百通了。

在快速入门一节已经介绍了@EnableFeignClients的基本作用,它就像是Feign的总开关,一切Feign的相关的操作都是从它开始的。@EnableFeignClients有三个作用,一是是引入FeignClientsRegistrar;二是指定扫描FeignClient的package信息,就是指定你所有FeignClient所在的包名;三是指定FeignClient的自定义配置类。

@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
@Documented
//ImportBeanDefinitionRegistrar的子类,用于处理@FeignClient注解。
@Import(FeignClientsRegistrar.class)
public @interface EnableFeignClients {

	/**
	 * 下面三个函数都是为了指定需要扫描的basepackage。
	 **/
	String[] value() default {};
	String[] basePackages() default {};

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


	/**
	 * 指定自定义feign client的自定义configuration,可以配置Decoder,Encoder和Contract,FeignClientsConfiguration是默认的配置类
	 */
	Class<?>[] defaultConfiguration() default {};

	/**
	 * 指定被@FeignClient修饰的类,如果不为空,那么路径自动检测机制会被关闭
	 * List of classes annotated with @FeignClient. If not empty, disables classpath scanning.
	 * @return
	 */
	Class<?>[] clients() default {};
}

FeignClientsRegistrarImportBeanDefinitionRegistrar的子类,Spring用ImportBeanDefinitionRegistrar来动态注册BeanDefinition。Feign通过FeignClientsRegistrar来处理@FeignClient修饰的FeignClient类,将这些接口的BeanDefinition注册到Spring容器中。这样就可以使用@Autowired来自动装载这些FeignClient的Bean实例,从而可以调用这些实例的方法发送网络请求。

class FeignClientsRegistrar implements ImportBeanDefinitionRegistrar,
		ResourceLoaderAware, BeanClassLoaderAware, EnvironmentAware {
	//....代码有删减
	@Override
	public void registerBeanDefinitions(AnnotationMetadata metadata,
			BeanDefinitionRegistry registry) {
    //从EnableFeignClients的属性值来构建Feign的自定义Configuration进行注册
		registerDefaultConfiguration(metadata, registry);
    //扫描package,注册被@FeignClient修饰的接口类的bean信息
		registerFeignClients(metadata, registry);
	}
	//代码有删减
}

FeignClientsRegistrarregisterBeanDefinitions函数主要做了两个事情,一是注册@EnableFeignClients提供的自定义配置类中的相关Bean信息,二是根据@EnableFeignClients提供的包信息扫描被@FeignClient修饰的FeignCleint接口类,然后进行注册。

下面的文章将会关注其他核心类的实现。

(完)