Spring Cloud Feign 自定義配置(重試、攔截與錯誤碼處理) 代碼實踐
基于 spring-boot-starter-parent 2.1.9.RELEASE, spring-cloud-openfeign 2.1.3.RELEASE
引子
Feign 是一個聲明式、模板化的HTTP客戶端,簡化了系統(tǒng)發(fā)起Http請求。創(chuàng)建它時,只需要創(chuàng)建一個接口,然后加上FeignClient注解,使用它時,就像調(diào)用本地方法一樣,作為開發(fā)者的我們完全感知不到這是在調(diào)用遠(yuǎn)程的方法,也感知不到背后發(fā)起了HTTP請求:
/**
* @author axin
* @suammry xx 客戶端
*/
@FeignClient(value = "xxClient",url = "${xx.host:www.axin.com}")
public interface DemoClient {
@PostMapping(value = "/xxx/url", headers = "Content-Type=application/json"})
yourResponse requestHTTP(@RequestBody JSONObject param);
}
上述的代碼就是一個定義一個Feign HTTP 客戶端,在其他類中只需要 @Autowired DemoClient,就可以像調(diào)用本地方法一樣發(fā)起HTTP請求。
介紹就到這,接下來進(jìn)入主題,因為 FeignClient 將發(fā)起HTTP請求與解析返回報文都做了包裝,如果你的業(yè)務(wù)場景需要定制一些調(diào)用機(jī)制,比如:
- 我想在發(fā)起請求響應(yīng)超時失敗時自動重試 —— 自定義重試機(jī)制
- 我想單獨對某些異常的HTTP狀態(tài)碼特殊處理 —— 自定義ErrorDecoder
- 服務(wù)端接口需要驗證簽名,所以我方在發(fā)起請求時要生成簽名然后傳過去 —— 定義 Fegin 攔截器
基于此,本文就以上述3個需求場景為例來介紹如何自定義 FeignClient 的配置
FeignClient的默認(rèn)配置類
Feign Client 默認(rèn)的配置類為 FeignClientsConfiguration, 這個類在 spring-cloud-netflix-core 的 jar 包下。
默認(rèn)注入了很多 Feign 相關(guān)的配置Bean,包括FeignRetryer、 FeignLoggerFactory 和 FormattingConversionService 等。另外,Decoder、Encoder和 Contract 這3個類在沒有Bean被注入的情況下,會自動注入默認(rèn)配置的 Bean,即ResponseEntity Decoder、SpringEncoder 和 SpringMvcContract。
如果你不知道如何自己定義配置時,不放點進(jìn)去看看人家默認(rèn)配置是如何實現(xiàn)的。這里就不曬源碼了。
FeignClient 注解參數(shù)
每個注解參數(shù)都做了注釋,詳情請見下方源碼:
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface FeignClient {
/**
* 指定FeignClient的名稱,如果項目使用了Ribbon,name屬性會作為微服務(wù)的名稱,用于服務(wù)發(fā)現(xiàn)
*/
@AliasFor("name")
String value() default "";
@Deprecated
String serviceId() default "";
@AliasFor("value")
String name() default "";
/**
* Sets the <code>@Qualifier</code> value for the feign client.
* 這個bean在應(yīng)用上下文中的名字為接口的全限定名,你也可以使用 @FeignClient 注解中的 qualifier 屬性給bean指定一個別名
*/
String qualifier() default "";
/**
* url地址
*/
String url() default "";
/**
* 當(dāng)發(fā)生404錯誤,如果該字段為true,會調(diào)用decoder進(jìn)行解碼,否則拋出FeignException
*/
boolean decode404() default false;
/**
* 指定FeignClient 的配置類,優(yōu)先級最高,默認(rèn)的配置類為 FeignClientsConfiguration類
*/
Class<?>[] configuration() default {};
/**
* 配置熔斷器的處理類
*/
Class<?> fallback() default void.class;
/**
* 工廠類,用于生產(chǎn)fallback類示例,通過這個屬性我們可以實現(xiàn)每個接口通用的容錯邏輯,減少重復(fù)代碼
*/
Class<?> fallbackFactory() default void.class;
/**
* 定義統(tǒng)一的路徑前綴
*/
String path() default "";
/**
* Whether to mark the feign proxy as a primary bean. Defaults to true.
*/
boolean primary() default true;
}
自定義Feign配置類
在 Spring Cloud 中,你可以通過 @FeignClient 注解聲明額外的配置(比 FeignClientsConfiguration 級別高)去控制feign客戶端,以一開始的feign接口為例:
/**
* @author axin
* @suammry xx 客戶端
*/
@FeignClient(value = "xxClient",url = "${xx.host:www.axin.com}",configuration = MyConfiguration.class)
public interface DemoClient {
@PostMapping(value = "/xxx/url", headers = "Content-Type=application/json"})
yourResponse requestHTTP(@RequestBody JSONObject param);
}
在上面這個示例中,feign客戶端在MyConfiguration中的配置將會覆蓋FeignClientsConfiguration中的配置。
要注意的是: MyConfiguration不需要使用@Configuration注解。如果加上了,它將全局生效。
Retryer-重試機(jī)制的自定義
/**
* @author axin
* @summary fegin 客戶端的自定義配置
*/
public class MyConfiguration {
/**
* 自定義重試機(jī)制
* @return
*/
@Bean
public Retryer feignRetryer() {
//fegin提供的默認(rèn)實現(xiàn),最大請求次數(shù)為5,初始間隔時間為100ms,下次間隔時間1.5倍遞增,重試間最大間隔時間為1s,
return new Retryer.Default();
}
}
ErrorDecoder-錯誤解碼器的自定義
當(dāng)feign調(diào)用返回HTTP報文時,會觸發(fā)這個方法,方法內(nèi)可以獲得HTTP狀態(tài)碼,可以用來定制一些處理邏輯等等。
/**
* @author axin
* @summary fegin 客戶端的自定義配置
*/
@Slf4j
public class MyConfiguration {
/**
* 自定義重試機(jī)制
* @return
*/
@Bean
public Retryer feignRetryer() {
//最大請求次數(shù)為5,初始間隔時間為100ms,下次間隔時間1.5倍遞增,重試間最大間隔時間為1s,
return new Retryer.Default();
}
@Bean
public ErrorDecoder feignError() {
return (key, response) -> {
if (response.status() == 400) {
log.error("請求xxx服務(wù)400參數(shù)錯誤,返回:{}", response.body());
}
if (response.status() == 409) {
log.error("請求xxx服務(wù)409異常,返回:{}", response.body());
}
if (response.status() == 404) {
log.error("請求xxx服務(wù)404異常,返回:{}", response.body());
}
// 其他異常交給Default去解碼處理
// 這里使用單例即可,Default不用每次都去new
return new ErrorDecoder.Default().decode(key, response);
};
}
}
采用了lambda的寫法,response變量是Response類型,通過status()方法可以拿到返回的HTTP狀態(tài)碼,body()可以獲得到響應(yīng)報文。
Feign攔截器實踐
攔截器在請求發(fā)出之前執(zhí)行,在攔截器代碼里可以修改請求參數(shù),header等等,如果你有簽名生成的需求,可以放在攔截器中來實現(xiàn)
/**
* @author axin
* @summary fegin 客戶端的自定義配置
*/
@Slf4j
public class MyConfiguration {
/**
* 自定義重試機(jī)制
* @return
*/
@Bean
public Retryer feignRetryer() {
//最大請求次數(shù)為5,初始間隔時間為100ms,下次間隔時間1.5倍遞增,重試間最大間隔時間為1s,
return new Retryer.Default();
}
@Bean
public ErrorDecoder feignError() {
return (key, response) -> {
if (response.status() == 400) {
log.error("請求xxx服務(wù)400參數(shù)錯誤,返回:{}", response.body());
}
if (response.status() == 409) {
log.error("請求xxx服務(wù)409異常,返回:{}", response.body());
}
if (response.status() == 404) {
log.error("請求xxx服務(wù)404異常,返回:{}", response.body());
}
// 其他異常交給Default去解碼處理
// 這里使用單例即可,Default不用每次都去new
return new ErrorDecoder.Default().decode(key, response);
};
}
/**
* fegin 攔截器
* @return
*/
@Bean
public RequestInterceptor cameraSign() {
return template -> {
// 如果是get請求
if (template.method().equals(Request.HttpMethod.GET.name())) {
//獲取到get請求的參數(shù)
Map<String, Collection<String>> queries = template.queries();
}
//如果是Post請求
if (template.method().equals(Request.HttpMethod.POST.name())) {
//獲得請求body
String body = template.requestBody().asString();
JSONPObject request = JSON.parseObject(body, JSONPObject.class);
}
//Do what you want... 例如生成接口簽名
String sign = "根據(jù)請求參數(shù)生成的簽名";
//放入url?之后
template.query("sign", sign);
//放入請求body中
String newBody = "原有body" + sign;
template.body(Request.Body.encoded(newBody.getBytes(StandardCharsets.UTF_8), StandardCharsets.UTF_8));
};
}
}
可以看到代碼中給了如何獲取請求參數(shù)和修改請求參數(shù)的示例。
總結(jié)
小結(jié)一下,對于開頭提出的場景:
- 我想在發(fā)起請求響應(yīng)超時失敗時自動重試 —— 自定義重試機(jī)制
- 我想單獨對某些異常的HTTP狀態(tài)碼特殊處理 —— 自定義ErrorDecoder
- 服務(wù)端接口需要驗證簽名,所以我方在發(fā)起請求時要生成簽名然后傳過去 —— 定義 Fegin 攔截器
給出了自定義 feign 配置的方式實現(xiàn)的樣例代碼,希望對你有用,如果有更好的方式簡化HTTP請求,歡迎留言分享~
參考鏈接
總結(jié)
到此這篇關(guān)于Spring Cloud Feign 自定義配置(重試、攔截與錯誤碼處理) 實踐的文章就介紹到這了,更多相關(guān)Spring Cloud Feign 自定義配置內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
JDBC下Idea添加mysql-jar包的詳細(xì)過程
這篇文章主要介紹了JDBC下Idea添加mysql-jar包的詳細(xì)過程,添加jar包首先到官網(wǎng)下載jar包,然后idea導(dǎo)入jar包,在就是檢查,本文給大家介紹的非常詳細(xì),對大家的學(xué)習(xí)或工作具有一定的參考借鑒價值,需要的朋友可以參考下2022-11-11
response.sendRedirect()實現(xiàn)重定向(頁面跳轉(zhuǎn))
在Java web開發(fā)中,使用response.sendRedirect()可實現(xiàn)重定向功能。本文將介紹如何使用該方法進(jìn)行頁面跳轉(zhuǎn),以及該方法的使用場景和注意事項,感興趣的可以了解一下2023-04-04
SpringBoot與spring security的結(jié)合的示例
這篇文章主要介紹了SpringBoot與spring security的結(jié)合的示例,小編覺得挺不錯的,現(xiàn)在分享給大家,也給大家做個參考。一起跟隨小編過來看看吧2018-03-03
mybatis實現(xiàn)mapper配置并查詢數(shù)據(jù)的思路詳解
這篇文章主要介紹了mybatis實現(xiàn)mapper配置并查詢數(shù)據(jù),本文給大家介紹的非常詳細(xì),對大家的學(xué)習(xí)或工作具有一定的參考借鑒價值,需要的朋友可以參考下2021-04-04
Java開發(fā)者就業(yè)需要掌握的9大專業(yè)技能
這篇文章主要為大家詳細(xì)介紹了java就業(yè)前需要掌握的專業(yè)技能,感興趣的小伙伴們可以參考一下2016-09-09
多線程計數(shù),怎么保持計數(shù)準(zhǔn)確的方法
這篇文章主要介紹了多線程計數(shù)的方法,有需要的朋友可以參考一下2014-01-01

