feign的作用
是将http请求抽象化为一个interface客户端,可以调用接口的形式来执行http请求,以达到简化http调用的目的。
feign将分散在@feignclient,@enablefeignclients,标识接口,接口方法,spring环境上的各种配置信息提取出来封装成一个对象,然后将对象里的信息注入到resttemplate中,生成一次http请求,然后执行。
正常在springmvc的controller
是将http请求的信息提取出来注入@requestmapping标识的方法中;而feign是将接口中的信息提取出来,封装成一个http请求的相关信息,是对springmvc解析过程的一个逆向处理。
当我们通过ioc注入接口对象时,得到的肯定是此接口的实现类对象,这个对象应该就是springcloud通过动态代理生成的对象。对于接口对象生成动态代理对象,一般选用jdk的proxy,这样实现简单且耦合性低,springcloud就是如此。
springcloud将@feignclient标识的接口
注册成一个 feignclientfactorybean 类型的bean对象,我们通过ioc注入的是此bean的 getobject( ) 得到的对象,这篇文章主要就是讲解此方法的执行过程。
当然直接贴源码那太无脑了,我主要是会将解析的过程总结成一个个点
让大家明白在使用过程中需要注意以及可以灵活拓展的地方
在解析接口前,先加载springcloud的feign配置,默认情况先加载 @feignclient,@enablefeignclients注解上的配置,其次加载 spring环境里 feign.client.default 指定的配置,最后加载 feign.client.appname(应用名称) 指定的配置后续的配置信息会覆盖之前的,也就是越靠后的优先级越高。可以通过 “feign.client.defaulttoproperties” 属性眼线液怎么画来改变这种优先级顺序验证:接口方法参数长度不能为0验证:标识@feignclient的接口最多只能继承一个接口验证:@feignclient标识的接口的父接口不能再继承自其它接口,也就是@feignclient的接口最多也只能有一个上级接口解析接口方法时, 忽略这些类型的方法:object的方法,static方法,default方法将@feignclient标识接口的最上级 interface 的@requestmapping注解的 value()值 设置为 methodmetadata里的requesttemplate的 “url” 的第一位;也就是说如果@feignclient标识接口 有susin120per interface,那么取super interface 的@requestmapping;如果没有,那么取自己的@requestmapping;如果都没有此注解,那么忽略如果 method 上未标识 @requestmapping,忽略method上的@requestmapping ,其 method()和value()的值都最多只能有一个将method上 @requestmapping 的 value() 追加到 requesttemplate的 “url” 上,接在 接口上的 @requestmapping 的value() 之后,机制匹配controller。解析method上 @requestmapping 上的 produces(),验证其值只能有一个元素,将其值添加到header上的 accept 中,比如 accept=application/json解析 method上@requestmapping 上的 consumes(感伤的个性签名),验证其值只能有一个元素,将其值添加到header上的 content-type中,比如 content-type=application/json解析 method上@requestmapping 上的 headers(),headers是一个string[],其元素是一个个的键值对,value可以使用 “${ }”来获取环境变量的值,比如urname=${spring.application.name}解析参数上的 @pathvariable 注解,如果 此注解上的 value()= id ,若 “{ id }” 不存在与 url , headers,queries中,那么将 “id” 加入methodmetadata 的 formparams 属性中,一般不容易出现这种情况解析参数上的 @requestheader 注解,如果此参数类型是map,设置下methodmetadata 里的headermapindex,也就是参数序号;如果不是,假设value()= uname,那么将uname 和 参数值 作为键值对 加入到methodmetadata 的 template(requesttemplate ) 的 headers 属性中解析参数上的 @requestparam注解, 如果此参数类型是map, 设置下methodmetadata 里的querymapindex, 也就是参数序号;如果不是,假设value()= uname,那么将uname 和 参数值 作为键值对 加入到methodmetadata 的 template(requesttemplate ) 的 queries属性中@pathvariable,@requestheader, @requestparam 这三个注解起作用的前提是springmvc里有他们的转换器,能够将他们转换为string。也就是说比如参数类型是date,需要自定义一个date > string 的转换器,注入到conversionrvice里;其他复杂类型也可以自定义相应的转换器。也就是这三个注解不是只能标识基本数据类型,只要定义了相应的转化器,也可以标识复杂类型。一个参数可以标识以上3种注解,不同的注解执行时起不同的作用。不同的注解可能value()不同,也就是一个参数可能被放进多个地方,比如 ( @pathvariable(“name”) @requestheader(“id”) @requestparam (“flag”) string urname ) 。每一个注解都会将此参数顺序和value() 存入 methodmetadata 的 indextoname,以备后续执行时解析。只要参数标识上述3个注解中的一个,那么将参数序号和转换器放入 methodmetadata 的 indextoexpander 中;多种注解共用一个转换器,类型是 convertingexpander,也就是要将参数转化为http请求中的数据。如果参数上未标识上述3种注解,那么此参数作为又见一帘幽梦片尾曲 requestbody 的内容。一个方法中只能有一个未标识注解的参数,将参数的序号和实际类型放入 methodmetadata 的 bodyindex 和 bodytype 中。将methodmetadata(接口class和方法上的数据),@feignclient注解里的数据,spring环境里配置的数据都放进 synchronousmethodhandler 类型的对象中, 此对象将配合jdk的aop动态代理,代理对象执行相应方法时将其转发给synchronousmethodhandler美丽的近义词 执行,每一个method对应一个synchronousmethodhandler为@feignclient标识的接口创建jdk动态代理对象,invocationhandler类型为 :feigninvocationhandler,持有map< method, methodhandler > 类型的属性,在调用相应方法时转发给指定的 methodhandler 处理。
以上就是解析@feignclient接口的,生成相应接口的动态代理对象的过程。
最终所有信息都汇总到synchronousmethodhandler对象里,在实际执行http请求时,根据接口上的参数数据和methodhandler信息生成feign.request对象,此对象里装着当前http请求的所有信息,然后feign将这些信息拷贝到resttemplate中,就能执行相应的http请求。
希望能给大家一个参考,也希望大家多多支持www.887551.com。