声明式RESTFUL客户端:SpringCloud OpenFeigh
Posted 无情的代码Bug
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了声明式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来进行访问。
定义服务名为feign-service
服务消费者
导入maven依赖
@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接口类的自定义配置类。
1,可以配置encoder,decoder,contract组件,自定义feign client自定义配置类
2,被@FeignClient修饰的类
通过FeignClientsRegister处理@FeignClient修饰的FeignClient接口类,让这些接口类的BeanDefinition注册到spring容器,然后使用@Autowired自动装载Bean实例。
在FeignClientsRegistrar这个类中做了两件事,注册@EnableFeignClients提供自定义配置类的Bean实例,还有将@FeignClient注解的FeignClient接口类,进行Bean实例注册。
自定义配置类是被@Configuration修饰的类
1,获取到metadata关于EnableFeignClients的属性值键值对
2,如果EnableFeignClients配置了defaultConfiguration类,就进行下一步操作,如果没有,会使用默认FeignConfiguration
BeanDefinitionRegistry是动态注册BeanDefinition的接口,registerBeanDefinition方法可以将BeanDefinition注册到Spring容器中。
使用BeanDefinitionBuilder生成BeanDefinition,然后让registry注册到spring容器上。
Specification是一个接口类,实现类是FeignClientSpecification,,它持有自定义配置类提供的组件实例,给OpenFeign使用。使用NamedContextFactory,创建指定的上下文对象,让对应的specification在这些上下文创建Bean实例。
1,获取该name所对应configuration,如果有的话,注册到子context中
2,注册default的Configuration,就是registerDefaultConfiguration
1,设置子context的Environment的propertySource属性源
2,所有的context的parent都相同,为applicationContext
NamedContextFactory创建出AnnotationConfigApplicationContext实例,每个AnnotationConfigApplicationContext实例都会注册配置类,给出基于组件实例,基于name管理一系列的组件实例,为不同的Feign Client准备不同配置实例,比如Decoder,Encoder。
扫描类信息
FeignClientsRegister做的第二件事呢就是扫描指定包下的类文件。注册@FeignClient注解接口类信息。
1,生成自定义的ClassPathScanningProvider
2,获取EnableFeignClients所有属性的键值对
1,只会扫描出被FeignClient修饰的类
2,需要扫描的包
3,遍历获取的basePackages。
4,获取basePackages下的所有beanDefinition,从这些beanDefinition获取FeignClient属性值
5,对某个FeignClient的Configuration进行设置
registerFeignClients方法依据@EnableFeignClients的属性获取要扫描的包路径信息,获取这些包下所有被@FeignClient注解修饰的接口类的BeanDefinition,调用registerFeignClient动态注册BeanDefinition。
实例初始化
FeignClientFactoryBean工厂类,Spring容器通过getObject方法获取Bean实例,获取@FeignClient修饰的接口类。
1,getOptional 方法调用了FeignContext的getInstance方法,从FeignContext的子上下文获取到Client类型的Bean实例。
2,因为有具体的url,所有不需要负载均衡,去除
Targeter是一个接口,target方法会生成对应的实例对象。OpenFeign使用HystrixTargeter这一层抽象封装Hystrix实现。
DefaultTargeter调用了Feign.Builder的target方法。
Feign.Builder是被FeignClientFactoryBean对象的feign方法创建。
Feign.Builder负责生成被@FeignClient修饰的接口类实例。
ReflectiveFeign的newInstance方法,一是扫描FeignClient接口类所有函数,生成对应的handler,二是使用Proxy生成FeignClient实例对象。
1,为每个方法生成一个DefaultMethodHandler
2,生成java effective的InvocationHandler
3,将defaultMethodHandler绑定到proxy中
扫描函数信息
ParseHandlerByName类的apply方法就是OpenFeign生成调用该函数时发送网络请求的模板,RequestTemplate实例。RequestTemplate包含网络发送请求的url和函数参数信息,@RequestMapping , @PathVariable注解信息。
1,使用contract来解析接口类中的函数信息
2,为每个函数生成一个BuildTemplateByResolvingArgs对象
3,最后使用factory来创建MethodHanlder实例。
使用Contract接口默认实现是SpringMvcContract。
1,调用BaseContract的parseAndValidateMetadata方法
1,函数的返回值
2,函数Feign相关的唯一配置键
3,获取处理修饰class的注解信息
4,调用子类processAnnotationOnclass的实现
5,处理修饰method的注解
6,函数的参数类型
7,函数参数的注解类型
8,依次处理各个函数的注解
9,处理参数的注解
processAnnotationOnClass处理接口类的注解。
如果targetType只继承或者实现了一种接口时,先处理继承的接口的注解,再处理targetType的注解。所以这种情况下parseAndValidateMetadata。
1,获取RequestMapping的注解信息
2,发送请求的path,设置methodMetadata.template的数据
processAnnotationOnMethod方法主要作用是处理修饰函数的注解,首先被校验该函数是否被@RequestMapping修饰,然后获取该函数所对应的HTTP请求的方式,默认GET,接着处理pathValue,value属性/instance/{instanceId},那么pathValue就是instanceId。
1,处理HTTP Method
2,默认的method是GET
最后处理消费和生成相关的信息。
processAnnotationsOnParameter方法修饰函数的注解
根据注解类型调用不同的AnnotatedParameterProcessor实现类。
1,遍历所有的参数注解
2,不同的注解类型有不同的Processor
3,没有缓存的Processor,生成一个
AnnotatedParameterProcessor是一个接口,有三个实现类:PathVariableParameterProcessor,RequestHeaderParameterProcessor,RequestParameterProcessor分别处理@RequestParam,@RequestHeader ,@PathVariable
PathVariableParameterProcessor的processArgument方法处理被@PathVariable注解修饰的参数。
ParseHandlersByName的apply方法,通过Contract的parseAndValidateMetadata方法获得接口类所有方法的元数据,apply方法就是为每个方法生成一个MethodHandler,根据这些元数据,包括路径,参数,头部,body。
生成Proxy接口类
OpenFeign使用Proxy的newProxyInstance方法来创建FeignClient接口类,将InvocationHandler绑定到接口类上。
当调用接口类实例的函数,会直接调用到FeignInvocationHandler的invoke方法。
invoke方法会根据函数名称来调用不同的MethodHandler实例的invoke方法。
函数调用和网络请求
最终函数会调用SynchronousMethoHandler的invoke方法。OpenFeign发送网络请求将参数添加到RequestTemplate中,调用Target生成具体的Request对象,然后调用Client发送网络请求。
RequestTemplate.Factory的create方法
遍历MethodMetadata中关于参数的索引对应名称的配置信息
2,参数的索引
3,expander转换器将各种类型的参数的值转换为string类型
4,设置queryMap参数
5,设置headersMap参数
1,对所有参数进行编码,对所有在RequestTemplate中的参数进行编码处理
2,SynchronousMethodHandler类的executeAndDecode方法根据RequestTemplate生成Request对象。
1,根据RequestTemplate生成Request
2,client发送请求,client可能为okhttpclient
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的主要内容,如果未能解决你的问题,请参考以下文章
Spring Boot 学习总结(33)—— Spring Boot 3 的声明式 HTTP 调用