vlambda博客
学习文章列表

声明式RESTFUL客户端:SpringCloud OpenFeigh

OpenFeign是一个声明式RESTful网络请求客户端,只需要使用OpenFeigh提供的注解修饰定义的网络请求的接口类。


REST是Resource Representation State Transfer “资源表现层状态转移”


啥意思呢?


Representation是“表现层”的意思,资源的外在表现形式。把资源外在呈现出来的叫做它的表现层。


文本用txt格式进行表现,也可以用xml格式,json格式和二进制格式。


视频可以用MP4格式表现,也可以用AVI格式。


URI代表资源的实体,不代表它的形式。具体表现形式应该用HTTP请求的头信息Accept和Content-type字段指定。


State Transfer “状态转移”,客户端想要操作服务端的资源,必须通过某种手段,让服务器资源发生状态转移。这种转移通过表现层进行转移,通过HTTP协议四个动作实现。分别为:获取资源的GET,新建和更新资源的POST,更新资源的PUT,删除资源的DELETE。


OpenFeigh会根据带有注解的函数信息构建出网络请求的模板,发送网络请求之前,OpenFeigh 将函数的参数值设置到请求模板。



服务提供者只需要提供对外的网络请求端口,具体实现使用springMvc实现

也可以使用Jersey。


服务提供者定义一个ServiceInstanceRestController供消费者使用OpenFeign来进行访问。

声明式RESTFUL客户端:SpringCloud OpenFeigh

定义服务名为feign-service

声明式RESTFUL客户端:SpringCloud OpenFeigh


服务消费者

声明式RESTFUL客户端:SpringCloud OpenFeigh

导入maven依赖


声明式RESTFUL客户端:SpringCloud OpenFeigh

@EnableFeignClient就是一个开关,使用了这个注解,相关组件才会生效。


在服务消费者定义一个FeignServiceClient,OpenFeign就会向feign-service服务的/feign-service/instance/{serviceId}接口发送网络请求。




源码分析


FeignClientFactoryBean是创建@FeignClient修饰的接口类Bean工厂类,由不同的FeignConfiguration配置类构造出来的不同实例,在FeignContext配置组件的上下文环境。SynchronousMethodHandler是methodHander的子类,在Feign Client 发送网络请求,将请求响应转化为函数返回值。


OpenFeign通过多种方式进行自定义配置,配置的变化会导致接口类使用不同的Bean实例,控制OpenFeign 的行为。网络请求的编解码,压缩,日志处理。



@EnableFeignClients 就像一个开关,OpenFeign的相关操作就是从它开始。这个注解有三个作用,第一个作用就是引入FeignClientsRegister;二就是指定扫描FeignClient包信息。三是指定FeignClient接口类的自定义配置类。


声明式RESTFUL客户端:SpringCloud OpenFeigh


1,可以配置encoder,decoder,contract组件,自定义feign client自定义配置类

2,被@FeignClient修饰的类


通过FeignClientsRegister处理@FeignClient修饰的FeignClient接口类,让这些接口类的BeanDefinition注册到spring容器,然后使用@Autowired自动装载Bean实例。


声明式RESTFUL客户端:SpringCloud OpenFeigh

在FeignClientsRegistrar这个类中做了两件事,注册@EnableFeignClients提供自定义配置类的Bean实例,还有将@FeignClient注解的FeignClient接口类,进行Bean实例注册。


自定义配置类是被@Configuration修饰的类

声明式RESTFUL客户端:SpringCloud OpenFeigh


1,获取到metadata关于EnableFeignClients的属性值键值对

2,如果EnableFeignClients配置了defaultConfiguration类,就进行下一步操作,如果没有,会使用默认FeignConfiguration



声明式RESTFUL客户端:SpringCloud OpenFeigh

BeanDefinitionRegistry是动态注册BeanDefinition的接口,registerBeanDefinition方法可以将BeanDefinition注册到Spring容器中。

使用BeanDefinitionBuilder生成BeanDefinition,然后让registry注册到spring容器上。



声明式RESTFUL客户端:SpringCloud OpenFeigh


声明式RESTFUL客户端:SpringCloud OpenFeigh

Specification是一个接口类,实现类是FeignClientSpecification,,它持有自定义配置类提供的组件实例,给OpenFeign使用。使用NamedContextFactory,创建指定的上下文对象,让对应的specification在这些上下文创建Bean实例。


声明式RESTFUL客户端:SpringCloud OpenFeigh


声明式RESTFUL客户端:SpringCloud OpenFeigh

1,获取该name所对应configuration,如果有的话,注册到子context中

2,注册default的Configuration,就是registerDefaultConfiguration

声明式RESTFUL客户端:SpringCloud OpenFeigh

1,设置子context的Environment的propertySource属性源

2,所有的context的parent都相同,为applicationContext


NamedContextFactory创建出AnnotationConfigApplicationContext实例,每个AnnotationConfigApplicationContext实例都会注册配置类,给出基于组件实例,基于name管理一系列的组件实例,为不同的Feign Client准备不同配置实例,比如Decoder,Encoder。


扫描类信息

FeignClientsRegister做的第二件事呢就是扫描指定包下的类文件。注册@FeignClient注解接口类信息。


声明式RESTFUL客户端:SpringCloud OpenFeigh

1,生成自定义的ClassPathScanningProvider

2,获取EnableFeignClients所有属性的键值对

声明式RESTFUL客户端:SpringCloud OpenFeigh

1,只会扫描出被FeignClient修饰的类

2,需要扫描的包

3,遍历获取的basePackages。

4,获取basePackages下的所有beanDefinition,从这些beanDefinition获取FeignClient属性值

5,对某个FeignClient的Configuration进行设置



registerFeignClients方法依据@EnableFeignClients的属性获取要扫描的包路径信息,获取这些包下所有被@FeignClient注解修饰的接口类的BeanDefinition,调用registerFeignClient动态注册BeanDefinition。


实例初始化


FeignClientFactoryBean工厂类,Spring容器通过getObject方法获取Bean实例,获取@FeignClient修饰的接口类。


声明式RESTFUL客户端:SpringCloud OpenFeigh

1,getOptional 方法调用了FeignContext的getInstance方法,从FeignContext的子上下文获取到Client类型的Bean实例。

2,因为有具体的url,所有不需要负载均衡,去除

声明式RESTFUL客户端:SpringCloud OpenFeigh

Targeter是一个接口,target方法会生成对应的实例对象。OpenFeign使用HystrixTargeter这一层抽象封装Hystrix实现。


声明式RESTFUL客户端:SpringCloud OpenFeigh


声明式RESTFUL客户端:SpringCloud OpenFeigh

DefaultTargeter调用了Feign.Builder的target方法。

Feign.Builder是被FeignClientFactoryBean对象的feign方法创建。

声明式RESTFUL客户端:SpringCloud OpenFeigh

声明式RESTFUL客户端:SpringCloud OpenFeigh

声明式RESTFUL客户端:SpringCloud OpenFeigh

Feign.Builder负责生成被@FeignClient修饰的接口类实例。

ReflectiveFeign的newInstance方法,一是扫描FeignClient接口类所有函数,生成对应的handler,二是使用Proxy生成FeignClient实例对象。


声明式RESTFUL客户端:SpringCloud OpenFeigh

1,为每个方法生成一个DefaultMethodHandler

2,生成java effective的InvocationHandler

3,将defaultMethodHandler绑定到proxy中



扫描函数信息

ParseHandlerByName类的apply方法就是OpenFeign生成调用该函数时发送网络请求的模板,RequestTemplate实例。RequestTemplate包含网络发送请求的url和函数参数信息,@RequestMapping , @PathVariable注解信息。


声明式RESTFUL客户端:SpringCloud OpenFeigh

声明式RESTFUL客户端:SpringCloud OpenFeigh

1,使用contract来解析接口类中的函数信息

2,为每个函数生成一个BuildTemplateByResolvingArgs对象

声明式RESTFUL客户端:SpringCloud OpenFeigh

3,最后使用factory来创建MethodHanlder实例。


使用Contract接口默认实现是SpringMvcContract。


声明式RESTFUL客户端:SpringCloud OpenFeigh

1,调用BaseContract的parseAndValidateMetadata方法


声明式RESTFUL客户端:SpringCloud OpenFeigh

1,函数的返回值

2,函数Feign相关的唯一配置键

3,获取处理修饰class的注解信息

声明式RESTFUL客户端:SpringCloud OpenFeigh

4,调用子类processAnnotationOnclass的实现

5,处理修饰method的注解

6,函数的参数类型

7,函数参数的注解类型

8,依次处理各个函数的注解

9,处理参数的注解



processAnnotationOnClass处理接口类的注解。

如果targetType只继承或者实现了一种接口时,先处理继承的接口的注解,再处理targetType的注解。所以这种情况下parseAndValidateMetadata。

声明式RESTFUL客户端:SpringCloud OpenFeigh

1,获取RequestMapping的注解信息

2,发送请求的path,设置methodMetadata.template的数据


声明式RESTFUL客户端:SpringCloud OpenFeigh

processAnnotationOnMethod方法主要作用是处理修饰函数的注解,首先被校验该函数是否被@RequestMapping修饰,然后获取该函数所对应的HTTP请求的方式,默认GET,接着处理pathValue,value属性/instance/{instanceId},那么pathValue就是instanceId。



1,处理HTTP Method

2,默认的method是GET



声明式RESTFUL客户端:SpringCloud OpenFeigh

最后处理消费和生成相关的信息。



processAnnotationsOnParameter方法修饰函数的注解


根据注解类型调用不同的AnnotatedParameterProcessor实现类。


声明式RESTFUL客户端:SpringCloud OpenFeigh


1,遍历所有的参数注解

2,不同的注解类型有不同的Processor

3,没有缓存的Processor,生成一个



AnnotatedParameterProcessor是一个接口,有三个实现类:PathVariableParameterProcessor,RequestHeaderParameterProcessor,RequestParameterProcessor分别处理@RequestParam,@RequestHeader ,@PathVariable


声明式RESTFUL客户端:SpringCloud OpenFeigh

声明式RESTFUL客户端:SpringCloud OpenFeigh

PathVariableParameterProcessor的processArgument方法处理被@PathVariable注解修饰的参数。


ParseHandlersByName的apply方法,通过Contract的parseAndValidateMetadata方法获得接口类所有方法的元数据,apply方法就是为每个方法生成一个MethodHandler,根据这些元数据,包括路径,参数,头部,body。



生成Proxy接口类


OpenFeign使用Proxy的newProxyInstance方法来创建FeignClient接口类,将InvocationHandler绑定到接口类上。



当调用接口类实例的函数,会直接调用到FeignInvocationHandler的invoke方法。


声明式RESTFUL客户端:SpringCloud OpenFeigh


invoke方法会根据函数名称来调用不同的MethodHandler实例的invoke方法。




函数调用和网络请求


最终函数会调用SynchronousMethoHandler的invoke方法。OpenFeign发送网络请求将参数添加到RequestTemplate中,调用Target生成具体的Request对象,然后调用Client发送网络请求。


声明式RESTFUL客户端:SpringCloud OpenFeigh




RequestTemplate.Factory的create方法


声明式RESTFUL客户端:SpringCloud OpenFeigh

遍历MethodMetadata中关于参数的索引对应名称的配置信息


声明式RESTFUL客户端:SpringCloud OpenFeigh

2,参数的索引

3,expander转换器将各种类型的参数的值转换为string类型


声明式RESTFUL客户端:SpringCloud OpenFeigh

4,设置queryMap参数

5,设置headersMap参数



声明式RESTFUL客户端:SpringCloud OpenFeigh

1,对所有参数进行编码,对所有在RequestTemplate中的参数进行编码处理

2,SynchronousMethodHandler类的executeAndDecode方法根据RequestTemplate生成Request对象。



声明式RESTFUL客户端:SpringCloud OpenFeigh

1,根据RequestTemplate生成Request

2,client发送请求,client可能为okhttpclient



声明式RESTFUL客户端:SpringCloud OpenFeigh

OpenFeign提供了RequestInterceptor机制,在RequestTemplate生成Request的过程,调用所有RequestInterceptor对RequestTemplate进行处理。使用请求拦截器为每个请求添加固定的header信息。例如BasicAuthRequestInterceptor添加Authorization header字段


Client用来发送网络请求的接口类。


OKHttpClient调用execute方法发送网络请求。



Decoder与Encoder定制化


Encoder将Object对象转化为HTTP请求的Body,Decoder将网络响应转化为对应的Object对象。



在OpenFeign中可以自定义配置类Decoder和Encoder自定义Bean实例。


CustomFeignConfig配置类将ResponseEntityDecoder和SpringEncoder配置为Feign的Decoder和Encoder。


请求响应压缩


在让OpenFiegn发送请求时进行GZIP压缩。


声明式RESTFUL客户端:SpringCloud OpenFeigh

选择性的压缩某种请求类型



设置请求的最小阈值大小