33張圖探秘OpenFeign核心架構(gòu)原理
大家好,我是三友~~
在很久之前,我寫過兩篇關(guān)于OpenFeign和Ribbon這兩個(gè)SpringCloud核心組件架構(gòu)原理的文章
但是說實(shí)話,從我現(xiàn)在的角度來看,這兩篇文章的結(jié)構(gòu)和內(nèi)容其實(shí)還可以更加完善
剛好我最近打算整個(gè)SpringCloud各個(gè)組件架構(gòu)原理的小冊(cè)子
所以趁著這個(gè)機(jī)會(huì),我就來重新寫一下這兩篇文章,彌補(bǔ)之前文章的不足
這一篇文章就先來講一講OpenFeign的核心架構(gòu)原理
整篇文章大致分為以下四個(gè)部分的內(nèi)容:
第一部分,脫離于SpringCloud,原始的Feign是什么樣的?
第二部分,F(xiàn)eign的核心組件有哪些,整個(gè)執(zhí)行鏈路是什么樣的?
第三部分,SpringCloud是如何把Feign融入到自己的生態(tài)的?
第四部分,OpenFeign有幾種配置方式,各種配置方式的優(yōu)先級(jí)是什么樣的?
好了,話不多說,接下來就直接進(jìn)入主題,來探秘OpenFeign核心架構(gòu)原理
原始Feign是什么樣的?
在日常開發(fā)中,使用Feign很簡(jiǎn)單,就三步
第一步:引入依賴
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-openfeign</artifactId>
<version>2.2.5.RELEASE</version>
</dependency>第二步:在啟動(dòng)引導(dǎo)類加上@EnableFeignClients注解
@SpringBootApplication
@EnableFeignClients
public class MyApplication {
public static void main(String[] args) {
SpringApplication.run(MyApplication.class, args);
}
}第三步:寫個(gè)FeignClient接口
@FeignClient(name = "order")
@RequestMapping("/order")
public interface OrderApiClient {
@GetMapping
Order queryOrder(@RequestParam("orderId") Long orderId);
}之后當(dāng)我們要使用時(shí),只需要注入OrderApiClient對(duì)象就可以了
雖然使用方便,但這并不是Feign最原始的使用方式,而是SpringCloud整合Feign之后的使用方式
Feign最開始是由Netflix開源的
后來SpringCloud就將Feign進(jìn)行了一層封裝,整合到自己的生態(tài),讓Feign使用起來更加簡(jiǎn)單
并同時(shí)也給它起了一個(gè)更高級(jí)的名字,OpenFeign
接下來文章表述有時(shí)可能并沒有嚴(yán)格區(qū)分Feign和OpenFeign的含義,你知道是這么個(gè)意思就行了。
Feign本身有自己的使用方式,也有類似Spring MVC相關(guān)的注解,如下所示:
public interface OrderApiClient {
@RequestLine("GET /order/{orderId}")
Order queryOrder(@Param("orderId") Long orderId);
}OrderApiClient對(duì)象需要手動(dòng)通過Feign.builder()來創(chuàng)建
public class FeignDemo {
public static void main(String[] args) {
OrderApiClient orderApiClient = Feign.builder()
.target(OrderApiClient.class, "http://localhost:8088");
orderApiClient.queryOrder(9527L);
}
}Feign的本質(zhì):動(dòng)態(tài)代理 + 七大核心組件
相信稍微了解Feign的小伙伴都知道,F(xiàn)eign底層其實(shí)是基于JDK動(dòng)態(tài)代理來的
所以Feign.builder()最終構(gòu)造的是一個(gè)代理對(duì)象
Feign在構(gòu)建動(dòng)態(tài)代理的時(shí)候,會(huì)去解析方法上的注解和參數(shù)
獲取Http請(qǐng)求需要用到基本參數(shù)以及和這些參數(shù)和方法參數(shù)的對(duì)應(yīng)關(guān)系
比如Http請(qǐng)求的url、請(qǐng)求體是方法中的第幾個(gè)參數(shù)、請(qǐng)求頭是方法中的第幾個(gè)參數(shù)等等
之后在構(gòu)建Http請(qǐng)求時(shí),就知道請(qǐng)求路徑以及方法的第幾個(gè)參數(shù)對(duì)應(yīng)是Http請(qǐng)求的哪部分?jǐn)?shù)據(jù)
當(dāng)調(diào)用動(dòng)態(tài)代理方法的時(shí)候,F(xiàn)eign就會(huì)將上述解析出來的Http請(qǐng)求基本參數(shù)和方法入?yún)⒔M裝成一個(gè)Http請(qǐng)求
然后發(fā)送Http請(qǐng)求,獲取響應(yīng),再根據(jù)響應(yīng)的內(nèi)容的類型將響應(yīng)體的內(nèi)容轉(zhuǎn)換成對(duì)應(yīng)的類型
這就是Feign的大致原理
圖片
在整個(gè)Feign動(dòng)態(tài)代理生成和調(diào)用過程中,需要依靠Feign的一些核心組件來協(xié)調(diào)完成
如下圖所示是Feign的一些核心組件
這些核心組件可以通過Feign.builder()進(jìn)行替換
由于組件很多,這里我挑幾個(gè)重要的跟大家講一講
1、Contract
圖片
前面在說Feign在構(gòu)建動(dòng)態(tài)代理的時(shí)候,會(huì)去解析方法上的注解和參數(shù),獲取Http請(qǐng)求需要用到基本參數(shù)
而這個(gè)Contract接口的作用就是用來干解析這件事的
Contract的默認(rèn)實(shí)現(xiàn)是解析Feign自己原生注解的
圖片
解析時(shí),會(huì)為每個(gè)方法生成一個(gè)MethodMetadata對(duì)象
圖片
MethodMetadata就封裝了Http請(qǐng)求需要用到基本參數(shù)以及這些參數(shù)和方法參數(shù)的對(duì)應(yīng)關(guān)系
SpringCloud在整合Feign的時(shí)候,為了讓Feign能夠識(shí)別Spring MVC的注解,所以就自己實(shí)現(xiàn)了Contract接口
2、Encoder
通過名字也可以看出來,這個(gè)其實(shí)用來編碼的
具體的作用就是將請(qǐng)求體對(duì)應(yīng)的方法參數(shù)序列化成字節(jié)數(shù)組
Feign默認(rèn)的Encoder實(shí)現(xiàn)只支持請(qǐng)求體對(duì)應(yīng)的方法參數(shù)類型為String和字節(jié)數(shù)組
圖片
如果是其它類型,比如說請(qǐng)求體對(duì)應(yīng)的方法參數(shù)類型為AddOrderRequest.class類型,此時(shí)就無法對(duì)AddOrderRequest對(duì)象進(jìn)行序列化
這就導(dǎo)致默認(rèn)情況下,這個(gè)Encoder的實(shí)現(xiàn)很難用
于是乎,Spring就實(shí)現(xiàn)了Encoder接口
圖片
可以將任意請(qǐng)求體對(duì)應(yīng)的方法參數(shù)類型對(duì)象序列化成字節(jié)數(shù)組
3、Decoder
Decoder的作用恰恰是跟Encoder相反
Encoder是將請(qǐng)求體對(duì)應(yīng)的方法參數(shù)序列化成字節(jié)數(shù)組
而Decoder其實(shí)就是將響應(yīng)體由字節(jié)流反序列化成方法返回值類型的對(duì)象
Decoder默認(rèn)情況下跟Encoder的默認(rèn)情況是一樣的,只支持反序列化成字節(jié)數(shù)組或者是String
所以,Spring也同樣實(shí)現(xiàn)了Decoder,擴(kuò)展它的功能
圖片
可以將響應(yīng)體對(duì)應(yīng)的字節(jié)流反序列化成任意返回值類型對(duì)象
4、Client

從接口方法的參數(shù)和返回值其實(shí)可以看出,這其實(shí)就是動(dòng)態(tài)代理對(duì)象最終用來執(zhí)行Http請(qǐng)求的組件
默認(rèn)實(shí)現(xiàn)就是通過JDK提供的HttpURLConnection來的
除了這個(gè)默認(rèn)的,F(xiàn)eign還提供了基于HttpClient和OkHttp實(shí)現(xiàn)的
在項(xiàng)目中,要想替換默認(rèn)的實(shí)現(xiàn),只需要引入相應(yīng)的依賴,在構(gòu)建Feign.builder()時(shí)設(shè)置一下就行了
SpringCloud環(huán)境底下會(huì)根據(jù)引入的依賴自動(dòng)進(jìn)行設(shè)置
除了上述的三個(gè)實(shí)現(xiàn),最最重要的當(dāng)然是屬于它基于負(fù)載均衡的實(shí)現(xiàn)
如下是OpenFeign用來整合Ribbon的核心實(shí)現(xiàn)
圖片
這個(gè)Client會(huì)根據(jù)服務(wù)名,從Ribbon中獲取一個(gè)服務(wù)實(shí)例的信息,也就是ip和端口
之后會(huì)通過ip和端口向服務(wù)實(shí)例發(fā)送Http請(qǐng)求
5、InvocationHandlerFactory
InvocationHandler我相信大家應(yīng)該都不陌生
對(duì)于JDK動(dòng)態(tài)代理來說,必須得實(shí)現(xiàn)InvocationHandler才能創(chuàng)建動(dòng)態(tài)代理
InvocationHandler的invoke方法實(shí)現(xiàn)就是動(dòng)態(tài)代理走的核心邏輯
而InvocationHandlerFactory其實(shí)就是創(chuàng)建InvocationHandler的工廠
所以,這里就可以猜到,通過InvocationHandlerFactory創(chuàng)建的InvocationHandler應(yīng)該就是Feign動(dòng)態(tài)代理執(zhí)行的核心邏輯
InvocationHandlerFactory默認(rèn)實(shí)現(xiàn)是下面這個(gè)
SpringCloud環(huán)境下默認(rèn)也是使用它的這個(gè)默認(rèn)實(shí)現(xiàn)
所以,我們直接去看看InvocationHandler的實(shí)現(xiàn)類FeignInvocationHandler
圖片
從實(shí)現(xiàn)可以看出,除了Object類的一些方法,最終會(huì)調(diào)用方法對(duì)應(yīng)的MethodHandler的invoke方法
所以注意注意,這個(gè)MethodHandler就封裝了Feign執(zhí)行Http調(diào)用的核心邏輯,很重要,后面還會(huì)提到
圖片
雖然說默認(rèn)情況下SpringCloud使用是默認(rèn)實(shí)現(xiàn),最終使用FeignInvocationHandler
但是當(dāng)其它框架整合SpringCloud生態(tài)的時(shí)候,為了適配OpenFeign,有時(shí)會(huì)自己實(shí)現(xiàn)InvocationHandler
比如常見的限流熔斷框架Hystrix和Sentinel都實(shí)現(xiàn)了自己的InvocationHandler
這樣就可以對(duì)MethodHandler執(zhí)行前后,也就是Http接口調(diào)用前后進(jìn)行限流降級(jí)等操作。
6、RequestInterceptor
圖片
RequestInterceptor它其實(shí)是一個(gè)在發(fā)送請(qǐng)求前的一個(gè)攔截接口
通過這個(gè)接口,在發(fā)送Http請(qǐng)求之前再對(duì)Http請(qǐng)求的內(nèi)容進(jìn)行修改
比如我們可以設(shè)置一些接口需要的公共參數(shù),如鑒權(quán)token之類的
@Component
public class TokenRequestInterceptor implements RequestInterceptor {
@Override
public void apply(RequestTemplate template) {
template.header("token", "token值");
}
}7、Retryer
這是一個(gè)重試的組件,默認(rèn)實(shí)現(xiàn)如下
默認(rèn)情況下,最大重試5次
在SpringCloud下,并沒有使用上面那個(gè)實(shí)現(xiàn),而使用的是下面這個(gè)實(shí)現(xiàn)
圖片
所以,SpringCloud下默認(rèn)是不會(huì)進(jìn)行重試
小總結(jié)
這一節(jié)主要是介紹了7個(gè)Feign的核心組件以及Spring對(duì)應(yīng)的擴(kuò)展實(shí)現(xiàn)
為了方便你查看,我整理了如下表格
接口 | 作用 | Feign默認(rèn)實(shí)現(xiàn) | Spring實(shí)現(xiàn) |
Contract | 解析方法注解和參數(shù),將Http請(qǐng)求參數(shù)和方法參數(shù)對(duì)應(yīng) | Contract.Default | SpringMvcContract |
Encoder | 將請(qǐng)求體對(duì)應(yīng)的方法參數(shù)序列化成字節(jié)數(shù)組 | Encoder.Default | SpringEncoder |
Decoder | 將響應(yīng)體的字節(jié)流反序列化成方法返回值類型對(duì)象 | Decoder.Default | SpringDecoder |
Client | 發(fā)送Http請(qǐng)求 | Client.Default | LoadBalancerFeignClient |
InvocationHandlerFactory | InvocationHandler工廠,動(dòng)態(tài)代理核心邏輯 | InvocationHandlerFactory.Default | 無 |
RequestInterceptor | 在發(fā)送Http請(qǐng)求之前,再對(duì)Http請(qǐng)求的內(nèi)容進(jìn)行攔截修改 | 無 | 無 |
Retryer | 重試組件 | Retryer.Default | 無 |
除了這些之外,還有一些其它組件這里就沒有說了
比如日志級(jí)別Logger.Level,日志輸出Logger,有興趣的可以自己查看
Feign核心運(yùn)行原理分析
上一節(jié)說了Feign核心組件,這一節(jié)我們來講一講Feign核心運(yùn)行原理,主要分為兩部分內(nèi)容:
- 動(dòng)態(tài)代理生成原理
- 一次Feign的Http調(diào)用執(zhí)行過程
1、動(dòng)態(tài)代理生成原理
這里我先把上面的Feign原始使用方式的Demo代碼再拿過來
public class FeignDemo {
public static void main(String[] args) {
OrderApiClient orderApiClient = Feign.builder()
.target(OrderApiClient.class, "http://localhost:8088");
orderApiClient.queryOrder(9527L);
}
}通過Demo可以看出,最后是通過Feign.builder().target(xx)獲取到動(dòng)態(tài)代理的
而上述代碼執(zhí)行邏輯如下所示:
圖片
最終會(huì)調(diào)用ReflectiveFeign的newInstance方法來創(chuàng)建動(dòng)態(tài)代理對(duì)象
而ReflectiveFeign內(nèi)部設(shè)置了前面提到的一些核心組件
接下我們來看看newInstance方法
這個(gè)方法主要就干兩件事:
第一件事首先解析接口,構(gòu)建每個(gè)方法對(duì)應(yīng)的MethodHandler
MethodHandler在前面講InvocationHandlerFactory特地提醒過
動(dòng)態(tài)代理(FeignInvocationHandler)最終會(huì)調(diào)用MethodHandler來處理Feign的一次Http調(diào)用
在解析接口的時(shí)候,就會(huì)用到前面提到的Contract來解析方法參數(shù)和注解,生成MethodMetadata,這里我代碼我就不貼了
第二件事通過InvocationHandlerFactory創(chuàng)建InvocationHandler
然后再構(gòu)建出接口的動(dòng)態(tài)代理對(duì)象
ok,到這其實(shí)就走完了動(dòng)態(tài)代理的生成過程
所以動(dòng)態(tài)代理生成邏輯很簡(jiǎn)單,總共也沒幾行代碼,畫個(gè)圖來總結(jié)一下
圖片
2、一次Feign的Http調(diào)用執(zhí)行過程
前面說了,調(diào)用接口動(dòng)態(tài)代理的方式時(shí),通過InvocationHandler(FeignInvocationHandler),最終交給MethodHandler的invoke方法來執(zhí)行
MethodHandler是一個(gè)接口,最終會(huì)走到它的實(shí)現(xiàn)類SynchronousMethodHandler的invoke方法實(shí)現(xiàn)
SynchronousMethodHandler中的屬性就是我們前面提到的一些組件
由于整個(gè)代碼調(diào)用執(zhí)行鏈路比較長,這里我就不截代碼了,有興趣的可以自己翻翻
不過這里我畫了一張圖,可以通過這張圖來大致分析整個(gè)Feign一次Http調(diào)用的過程
圖片
- 首先就是前面說的,進(jìn)入FeignInvocationHandler,找到方法對(duì)應(yīng)的SynchronousMethodHandler,調(diào)用invoke方法實(shí)現(xiàn)
- 之后根據(jù)MethodMetadata和方法的入?yún)?,?gòu)造出一個(gè)RequestTemplate,RequestTemplate封裝了Http請(qǐng)求的參數(shù),在這個(gè)過程中,如果有請(qǐng)求體,那么會(huì)通過Encoder序列化
- 然后調(diào)用RequestInterceptor,通過RequestInterceptor對(duì)RequestTemplate進(jìn)行攔截?cái)U(kuò)展,可以對(duì)請(qǐng)求數(shù)據(jù)再進(jìn)行修改
- 再然后將RequestTemplate轉(zhuǎn)換成Request,Request其實(shí)跟RequestTemplate差不多,也是封裝了Http請(qǐng)求的參數(shù)
- 接下來通過Client去根據(jù)Request中封裝的Http請(qǐng)求參數(shù),發(fā)送Http請(qǐng)求,得到響應(yīng)Response
- 最后根據(jù)Decoder,將響應(yīng)體反序列化成方法返回值類型對(duì)象,返回
這就是Feign一次Http調(diào)用的執(zhí)行過程
如果有設(shè)置重試,那么也是在這個(gè)階段生效的
SpringCloud是如何整合Feign的?
SpringCloud在整合Feign的時(shí)候,主要是分為兩部分
- 核心組件重新實(shí)現(xiàn),支持更多SpringCloud生態(tài)相關(guān)的功能
- 將接口動(dòng)態(tài)代理對(duì)象注入到Spring容器中
第一部分核心組件重新實(shí)現(xiàn)前面已經(jīng)都說過了,這里就不再重復(fù)了
至于第二部分我們就來好好講一講,Spring是如何將接口動(dòng)態(tài)代理對(duì)象注入到Spring容器中的
1、將FeignClient接口注冊(cè)到Spring中
使用OpenFeign時(shí),必須加上@EnableFeignClients
這個(gè)注解就是OpenFeign的發(fā)動(dòng)機(jī)
圖片
@EnableFeignClients最后通過@Import注解導(dǎo)入了一個(gè)FeignClientsRegistrar
圖片
FeignClientsRegistrar實(shí)現(xiàn)了ImportBeanDefinitionRegistrar
所以最終Spring在啟動(dòng)的時(shí)候會(huì)調(diào)用registerBeanDefinitions方法實(shí)現(xiàn)
之所以會(huì)調(diào)用registerBeanDefinitions方法,是@Import注解的作用,不清楚的同學(xué)可以看一下扒一扒Bean注入到Spring的那些姿勢(shì),你會(huì)幾種?
圖片
最終會(huì)走到registerFeignClients這個(gè)方法
這個(gè)方法雖然比較長,主要是干了下面這個(gè)2件事:
第一件事,掃描@EnableFeignClients所在類的包及其子包(如果有指定包就掃指定包),找出所有加了@FeignClient注解的接口,生成一堆BeanDefinition
這個(gè)BeanDefinition包含了這個(gè)接口的信息等信息
第二件事,將掃描到的這些接口注冊(cè)到Spring容器中
圖片
在注冊(cè)的時(shí)候,并非直接注冊(cè)接口類型,而是FeignClientFactoryBean類型
圖片
好了,到這整個(gè)@EnableFeignClients啟動(dòng)過程就結(jié)束了
雖然上面寫的很長,但是整個(gè)@EnableFeignClients其實(shí)也就只干了一件核心的事
掃描到所有的加了@FeignClient注解的接口
然后為每個(gè)接口生成一個(gè)Bean類型為FeignClientFactoryBean的BeanDefinition
最終注冊(cè)到Spring容器中
圖片
2、FeignClientFactoryBean的秘密
上一節(jié)說到,每個(gè)接口都對(duì)應(yīng)一個(gè)class類型為FeignClientFactoryBean的BeanDefinition
圖片
如上所示,F(xiàn)eignClientFactoryBean是一個(gè)FactoryBean
并且FeignClientFactoryBean的這些屬性,是在生成BeanDefinition的時(shí)候設(shè)置的
圖片
并且這個(gè)type屬性就是代表的接口類型
由于實(shí)現(xiàn)了FactoryBean,所以Spring啟動(dòng)過程中,一定為會(huì)調(diào)用getObject方法獲取真正的Bean對(duì)象
FactoryBean的作用就不說了,不清楚的小伙伴還是可以看看扒一扒Bean注入到Spring的那些姿勢(shì),你會(huì)幾種?這篇文章
getObject最終會(huì)走到getTarget()方法
圖片
從如上代碼其實(shí)可以看出來,最終還是會(huì)通過Feign.builder()來創(chuàng)建動(dòng)態(tài)代理對(duì)象
只不過不同的是,SpringCloud會(huì)替換Feign默認(rèn)的組件,改成自己實(shí)現(xiàn)的
總的來說,Spring是通過FactoryBean的這種方式,將Feign動(dòng)態(tài)代理對(duì)象添加到Spring容器中
OpenFeign的各種配置方式以及對(duì)應(yīng)優(yōu)先級(jí)
既然Feign核心組件可以替換,那么在SpringCloud環(huán)境下,我們?cè)撊绾稳ヅ渲米约旱慕M件呢?
不過在說配置之前,先說一下FeignClient配置隔離操作
在SpringCloud環(huán)境下,為了讓每個(gè)不同的FeignClient接口配置相互隔離
在應(yīng)用啟動(dòng)的時(shí)候,會(huì)為每個(gè)FeignClient接口創(chuàng)建一個(gè)Spring容器,接下來我就把這個(gè)容器稱為FeignClient容器
這些FeignClient的Spring容器有一個(gè)相同的父容器,那就是項(xiàng)目啟動(dòng)時(shí)創(chuàng)建的容器
圖片
SpringCloud會(huì)給每個(gè)FeignClient容器添加一個(gè)默認(rèn)的配置類FeignClientsConfiguration配置類
圖片
這個(gè)配置類就聲明了各種Feign的組件
圖片
所以,默認(rèn)情況下,OpenFeign就使用這些配置的組件構(gòu)建代理對(duì)象
知道配置隔離之后,接下來看看具體的幾種方式配置以及它們之間的優(yōu)先級(jí)關(guān)系
1、通過@EnableFeignClients注解的defaultConfiguration屬性配置
舉個(gè)例子,比如我自己手動(dòng)聲明一個(gè)Contract對(duì)象,類型為MyContract
public class FeignConfiguration {
@Bean
public Contract contract(){
return new MyContract();
}
}注意注意,這里FeignConfiguration我沒加@Configuration注解,原因后面再說
此時(shí)配置如下所示:
@EnableFeignClients(defaultConfiguration = FeignConfiguration.class)之后這個(gè)配置類會(huì)被加到每個(gè)FeignClient容器中,所以這個(gè)配置是對(duì)所有的FeignClient生效
并且優(yōu)先級(jí)大于默認(rèn)配置的優(yōu)先級(jí)
比如這個(gè)例子就會(huì)使得FeignClient使用我聲明的MyContract,而不是FeignClientsConfiguration中聲明的SpringMvcContract
2、通過@FeignClient注解的configuration屬性配置
還以上面的FeignConfiguration配置類舉例,可以通過@FeignClient注解配置
@FeignClient(name = "order", configuration = FeignConfiguration.class)此時(shí)這個(gè)配置類會(huì)被加到自己FeignClient容器中,注意是自己FeignClient容器
所以這種配置的作用范圍是自己的這個(gè)FeignClient
并且這種配置的優(yōu)先級(jí)是大于@EnableFeignClients注解配置的優(yōu)先級(jí)
3、在項(xiàng)目啟動(dòng)的容器中配置
前面提到,由于所有的FeignClient容器的父容器都是項(xiàng)目啟動(dòng)的容器
所以可以將配置放在這個(gè)項(xiàng)目啟動(dòng)的容器中
還以FeignConfiguration為例,加上@Configuration注解,讓項(xiàng)目啟動(dòng)的容器的掃描到就成功配置了
這種配置的優(yōu)先級(jí)大于前面提到的所有配置優(yōu)先級(jí)
并且是對(duì)所有的FeignClient生效
所以,這就是為什么使用注解配置時(shí)為什么配置類不能加@Configuration注解的原因,因?yàn)橐坏┍豁?xiàng)目啟動(dòng)的容器掃描到,這個(gè)配置就會(huì)作用于所有的FeignClient,并且優(yōu)先級(jí)是最高的,就會(huì)導(dǎo)致你其它的配置失效,當(dāng)然你也可以加@Configuration注解,但是一定不能被項(xiàng)目啟動(dòng)的容器掃到
4、配置文件
除了上面3種編碼方式配置,OpenFeign也是支持通過配置文件的方式進(jìn)行配置
并且也同時(shí)支持對(duì)所有FeignClient生效和對(duì)單獨(dú)某個(gè)FeignClient生效
對(duì)所有FeignClient生效配置:
feign:
client:
config:
default: # default 代表對(duì)全局生效
contract: com.sanyou.feign.MyContract對(duì)單獨(dú)某個(gè)FeignClient生效配置:
feign:
client:
config:
order: # 具體的服務(wù)名
contract: com.sanyou.feign.MyContract在默認(rèn)情況下,這種配置文件方式優(yōu)先級(jí)最高
但是如果你在配置文件中將配置項(xiàng)feign.client.default-to-properties設(shè)置成false的話,配置文件的方式優(yōu)先級(jí)就是最低了
feign:
client:
default-to-properties: false小總結(jié)
這一節(jié),總共總結(jié)了4種配置OpenFeign的方式以及它們優(yōu)先級(jí)和作用范圍
畫張圖來總結(jié)一下
圖片
如果你在具體使用的時(shí)候,還是遇到了一些優(yōu)先級(jí)的問題,可以debug這部分源碼,看看到底生效的是哪個(gè)配置
圖片
圖片































