Spring Cloud 遠(yuǎn)程調(diào)用 OpenFeign 這些知識點(diǎn),能顛覆你的認(rèn)知!
環(huán)境:SpringBoot2.7.12 + Spring Cloud2021.0.7
1. 概述
Spring Cloud Openfeign是一種聲明式、模板化的HTTP客戶端,主要用于在Spring Cloud微服務(wù)架構(gòu)中進(jìn)行服務(wù)調(diào)用。
相比于傳統(tǒng)的RestTemplate,Openfeign更加簡潔,開發(fā)者只需通過編寫一個接口并添加注解進(jìn)行配置,即可實(shí)現(xiàn)對服務(wù)提供方接口的綁定,而無需手動構(gòu)造請求和解析返回數(shù)據(jù)。
Openfeign的應(yīng)用,讓Spring Cloud微服務(wù)調(diào)用變得更加便捷。在服務(wù)消費(fèi)者中,只需通過接口方法即可進(jìn)行遠(yuǎn)程服務(wù)調(diào)用,就像調(diào)用本地方法一樣簡單。此外,F(xiàn)eign還集成了LoadBalancer,利用LoadBalancer維護(hù)服務(wù)提供方列表,實(shí)現(xiàn)輪詢調(diào)用服務(wù)提供者。
使用Spring Cloud Openfeign,開發(fā)者可以更加專注于業(yè)務(wù)邏輯而不是底層的HTTP請求,提高了開發(fā)效率和代碼可讀性。同時,Openfeign還支持自定義配置和擴(kuò)展,可以滿足不同場景下的需求。總之,Spring Cloud Openfeign是Spring Cloud微服務(wù)架構(gòu)中不可或缺的一部分,可以幫助開發(fā)者更加高效地進(jìn)行服務(wù)調(diào)用。
2. 準(zhǔn)備環(huán)境
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-openfeign</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-loadbalancer</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-circuitbreaker-resilience4j</artifactId>
</dependency>
開啟openfeign功能
@SpringBootApplication
@EnableFeignClients
public class SpringCloudComprehensiveApplication {
}
feign客戶端
@FeignClient(
url = "http://localhost:8088/demos",
name = "demoService"
)
public interface DemoFeign {
@GetMapping("/info/{id}")
public Object info(@PathVariable("id") Integer id) ;
}
以上DemoFeign就能被正確的使用了。接下來看看下面的那些知識點(diǎn)你是知道的
3. 知識盲區(qū)
盲區(qū)1:超時時間
默認(rèn)情況下feign調(diào)用超時時間如下:
/**
* 默認(rèn)超時時間
* <ul>
* <li>Connect Timeout: 10 seconds</li>
* <li>Read Timeout: 60 seconds</li>
* <li>Follow all 3xx redirects</li>
* </ul>
*/
public Options() {
this(10, TimeUnit.SECONDS, 60, TimeUnit.SECONDS, true);
}
定義
public class FeignClientFactoryBean {
// 讀超時時間
private int readTimeoutMillis = new Request.Options().readTimeoutMillis();
// 連接超時時間
private int connectTimeoutMillis = new Request.Options().connectTimeoutMillis();
}
編程方式自定義:你只需要提供Request.Options類型的Bean即可。
配置定義
#全局定義
feign.client.config.default.connect-timeout=3000
feign.client.config.default.read-timeout=3000
#具體服務(wù)定義
feign.client.config.demoService.connect-timeout=2000
feign.client.config.demoService.read-timeout=2000
盲區(qū)2:重試
feign的重試相信很多人都沒有玩過對吧?
如果feign沒有啟用斷路器功能(feign.circuitbreaker.enabled, 默認(rèn)值為false),那么會開啟retryer(重試)功能;默認(rèn)情況openfeign提供了如下配置:
@Bean
@Scope("prototype")
@ConditionalOnMissingBean
public Feign.Builder feignBuilder(Retryer retryer) {
return Feign.builder().retryer(retryer);
}
// 默認(rèn)還是個不支持重試的,所以我們需要自定義重試Bean
@Bean
@ConditionalOnMissingBean
public Retryer feignRetryer() {
return Retryer.NEVER_RETRY;
}
自定義重試bean
@Bean
public Retryer feignRetryer() {
Retryer.Default retryer = new Retryer.Default(100, SECONDS.toMillis(1), 2);
return retryer ;
}
這樣如果當(dāng)前環(huán)境沒有cricuitbreaker,那么這里的重試就能生效了。
盲區(qū)3:服務(wù)降級
通常定義了feign客戶端后,我們都會定義相應(yīng)的降級服務(wù),fallback或fallbackFactory,如果這兩個都配置了那誰才會生效呢?源碼如下:
class FeignCircuitBreakerTargeter implements Targeter {
public <T> T target(FeignClientFactoryBean factory, Feign.Builder feign, FeignContext context,
Target.HardCodedTarget<T> target) {
// ...
FeignCircuitBreaker.Builder builder = (FeignCircuitBreaker.Builder) feign;
String name = !StringUtils.hasText(factory.getContextId()) ? factory.getName() : factory.getContextId();
// 先判斷了fallback屬性,如果不是void,那么直接返回了
Class<?> fallback = factory.getFallback();
if (fallback != void.class) {
return targetWithFallback(name, context, target, builder, fallback);
}
Class<?> fallbackFactory = factory.getFallbackFactory();
if (fallbackFactory != void.class) {
return targetWithFallbackFactory(name, context, target, builder, fallbackFactory);
}
return builder(name, builder).target(target);
}
}
盲區(qū)4:primary屬性
在@FeignClient注解中有個primary屬性,你知道這個屬性有什么用嗎?
默認(rèn)每一個feign客戶端都被注冊為bean,并且每個bean都相當(dāng)于使用了@Primary注解修飾一樣,任何地方注入都是有限注入的該bean。它的用處還得從fallback屬性說起。如果定義了feign客戶端后對應(yīng)的fallback是需要實(shí)現(xiàn)當(dāng)前這個feign接口的,且還的注冊為bean對象。那么如果把這里的primary設(shè)置為false后,容器中此時可是存在兩個DemoFeign類型的bean的,這時候容器啟動就會報錯了。所以這里默認(rèn)就吧feign客戶端的primary設(shè)置為true就是解決這個問題的。示例如下:
@FeignClient(
url = "http://localhost:8088/demos",
name = "demoService",
fallback = DemoFeignFallback.class
primary = true // 默認(rèn)即為true
)
public interface DemoFeign {}
@Component
public class DemoFeignFallback implements DemoFeign {
}
盲區(qū)5:動態(tài)刷新超時時間
盲區(qū)1中已經(jīng)提到了超時時間問題,那都是寫靜態(tài)配置,那能不能動態(tài)配置呢?可以,完全可以,你只需下面這樣操作即可
#開啟刷新配置
feign.client.refresh-enabled=true
實(shí)現(xiàn)的原理也比較簡單就是:向容器中注冊了一個OptionsFactoryBean類型的bean且該Bean的作用域范圍是refresh。當(dāng)我們調(diào)用/refresh endpoint后就會刷新該Bean的配置信息。
先就列出上面5個知識點(diǎn)吧,看看你知道幾個?
完畢?。?!