1. 概述
在本教程中,我們將描述 Spring Cloud OpenFeign——一個用於 Spring Boot 應用的聲明式 REST 客户端。
Feign 通過可插拔的註解支持(包括 Feign 註解和 JAX-RS 註解)使編寫 Web 服務客户端變得更容易。
此外,Spring Cloud 還支持使用 Spring MVC 註解以及與 Spring Web 中相同的 HttpMessageConverters。
使用 Feign 的一個優點是,我們無需編寫任何代碼來調用服務,只需定義一個接口。
2. 依賴項
首先,我們將創建一個 Spring Boot Web 項目,並在我們的 pom.xml 文件中添加 spring-cloud-starter-openfeign 依賴項:
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-openfeign</artifactId>
</dependency>此外,我們需要添加spring-cloud-dependencies:
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-dependencies</artifactId>
<version>${spring-cloud.version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>我們可以在 Maven Central 上找到最新版本的 spring-cloud-starter-openfeign 和 spring-cloud-dependencies.
3. Feign 客户端
接下來,我們需要在主類中添加 @EnableFeignClients:
@SpringBootApplication
@EnableFeignClients
public class ExampleApplication {
public static void main(String[] args) {
SpringApplication.run(ExampleApplication.class, args);
}
}通過此註釋,我們允許掃描聲明為Feign客户端的接口。
然後,我們使用@FeignClient註解聲明一個Feign客户端:
@FeignClient(value = "jplaceholder", url = "https://jsonplaceholder.typicode.com/")
public interface JSONPlaceHolderClient {
@RequestMapping(method = RequestMethod.GET, value = "/posts")
List<Post> getPosts();
@RequestMapping(method = RequestMethod.GET, value = "/posts/{postId}", produces = "application/json")
Post getPostById(@PathVariable("postId") Long postId);
}在本示例中,我們已配置客户端從 JSONPlaceholder API 讀取數據。
在 @FeignClient 註解中傳遞的 value 參數是一個必填的任意客户端名稱,而通過 url 參數,我們指定了 API 的基本 URL。
此外,由於此接口是一個 Feign 客户端,我們可以使用 Spring Web 註解來聲明我們想要訪問的 API。
4. 配置
現在,務必理解的是每個 Feign 客户端都由一組可定製的組件組成。
Spring Cloud 針對每個命名的客户端,使用 FeignClientsConfiguration 類(如下一節所述,可進行自定義)創建一個新的默認組件集。
上述類包含以下 Bean:
- 解碼器 – ResponseEntityDecoder,封裝了 SpringDecoder,用於解碼 Response。
- 編碼器 – SpringEncoder 用於編碼 RequestBody。
- 日誌記錄器 – Slf4jLogger 是 Feign 的默認日誌記錄器。
- 合同 – SpringMvcContract,提供註解處理。
- Feign-Builder – HystrixFeign.Builder 用於構建組件。
- 客户端 – LoadBalancerFeignClient 或默認 Feign 客户端。
4.1. 自定義 Bean 配置
如果想要自定義一個或多個 Bean,我們可以通過創建 Configuration 類並將其添加到 FeignClient 註解中來覆蓋它們。
@FeignClient(value = "jplaceholder",
url = "https://jsonplaceholder.typicode.com/",
configuration = ClientConfiguration.class)public class ClientConfiguration {
@Bean
public OkHttpClient client() {
return new OkHttpClient();
}
}在此示例中,我們告訴 Feign 使用 OkHttpClient 代替默認的,以支持 HTTP/2。
Feign 支持多種客户端,用於不同的用例,包括 ApacheHttpClient,它會在請求中發送更多標頭,例如 Content-Length,某些服務器需要它。
要使用這些客户端,請不要忘記將所需的依賴項添加到我們的 pom.xml 文件中:
<dependency>
<groupId>io.github.openfeign</groupId>
<artifactId>feign-okhttp</artifactId>
</dependency>
<dependency>
<groupId>io.github.openfeign</groupId>
<artifactId>feign-httpclient</artifactId>
</dependency>我們可以在 Maven Central 上找到最新版本的 feign-okhttp 和 feign-httpclient。
4.2. 使用屬性進行配置
與其使用 Configuration 類,我們可以使用應用程序屬性來配置 Feign 客户端,如本 application.yaml 示例所示:
feign:
client:
config:
default:
connectTimeout: 5000
readTimeout: 5000
loggerLevel: basic通過這種配置,我們將超時時間設置為五秒,並將每個已聲明的客户端的日誌級別設置為基本。
最後,我們可以使用默認作為客户端名稱創建配置,以配置所有@FeignClient對象,或者可以聲明feign客户端名稱進行配置。
feign:
client:
config:
jplaceholder:如果同時存在 配置 Bean 和配置屬性,則配置屬性將覆蓋 配置 Bean 的值。
5. 攔截器
添加攔截器是 Feign 提供的另一個有用的功能。
攔截器可以執行各種隱式任務,從身份驗證到日誌記錄,應用於每個 HTTP 請求/響應。
在本節中,我們將實現自己的攔截器,同時還將使用 Spring Cloud OpenFeign 內置的攔截器。兩者都會為每個請求添加基本的身份驗證標頭。
5.1. 實現 RequestInterceptor
讓我們實現我們的自定義請求攔截器:
@Bean
public RequestInterceptor requestInterceptor() {
return requestTemplate -> {
requestTemplate.header("user", username);
requestTemplate.header("password", password);
requestTemplate.header("Accept", ContentType.APPLICATION_JSON.getMimeType());
};
}此外,為了將攔截器添加到請求鏈中,只需將此 Bean 添加到我們的 Configuration 類中,或者,正如我們之前所見,也可以在屬性文件中聲明它:
feign:
client:
config:
default:
requestInterceptors:
com.baeldung.cloud.openfeign.JSONPlaceHolderInterceptor5.2. 使用 BasicAuthRequestInterceptor
我們可以使用 Spring Cloud OpenFeign 提供的 BasicAuthRequestInterceptor 類:
@Bean
public BasicAuthRequestInterceptor basicAuthRequestInterceptor() {
return new BasicAuthRequestInterceptor("username", "password");
}現在就這麼簡單了。現在所有請求都將包含基本的身份驗證標頭。
6. Hystrix 支持
Feign 支持 Hystrix,因此如果已啓用它,我們可以實現降級模式
通過降級模式,當遠程服務調用失敗時,而不是生成異常,服務消費者將執行備用代碼路徑,嘗試通過其他方式執行操作。
為了實現這一目標,我們需要通過在 properties 文件中添加 feign.hystrix.enabled=true 來啓用 Hystrix。
這允許我們實現在服務失敗時調用的降級方法:
@Component
public class JSONPlaceHolderFallback implements JSONPlaceHolderClient {
@Override
public List<Post> getPosts() {
return Collections.emptyList();
}
@Override
public Post getPostById(Long postId) {
return null;
}
}為了讓 Feign 知道 fallback 方法已經提供,我們還需要在 @FeignClient</em/> 註解中設置我們的 fallback 類:
@FeignClient(value = "jplaceholder",
url = "https://jsonplaceholder.typicode.com/",
fallback = JSONPlaceHolderFallback.class)
public interface JSONPlaceHolderClient {
// APIs
}7. 日誌記錄
對於每個 Feign 客户端,默認情況下會創建一個日誌記錄器。
要啓用日誌記錄,我們應該在 application.properties 文件中使用客户端接口的包名進行聲明:
logging.level.com.baeldung.cloud.openfeign.client: DEBUG或者,如果我們想僅為某個特定客户端啓用日誌記錄,可以使用完整的類名:
logging.level.com.baeldung.cloud.openfeign.client.JSONPlaceHolderClient: DEBUG請注意,Feign 日誌僅響應 DEBUG 級別。
客户端可配置的 Logger.Level 指示日誌記錄的詳細程度:
public class ClientConfiguration {
@Bean
Logger.Level feignLoggerLevel() {
return Logger.Level.BASIC;
}
}可以選擇四種日誌級別:
- NONE – 不啓用日誌記錄,這是默認選項
- BASIC – 只記錄請求方法、URL 和響應狀態
- HEADERS – 記錄基本信息,包括請求和響應頭信息
- FULL – 記錄請求和響應的請求體、頭信息和元數據
8. 錯誤處理
Feign 的默認錯誤處理程序,ErrorDecoder.default,始終會拋出 FeignException。
現在,這種行為並不總是最實用的。因此,為了自定義拋出的異常,我們可以使用 CustomErrorDecoder:
public class CustomErrorDecoder implements ErrorDecoder {
@Override
public Exception decode(String methodKey, Response response) {
switch (response.status()){
case 400:
return new BadRequestException();
case 404:
return new NotFoundException();
default:
return new Exception("Generic error");
}
}
}然後,正如我們之前所做的那樣,我們需要通過向 Configuration 類添加一個 Bean 來替換默認的 ErrorDecoder。
public class ClientConfiguration {
@Bean
public ErrorDecoder errorDecoder() {
return new CustomErrorDecoder();
}
}9. 結論
在本文中,我們討論了 Spring Cloud OpenFeign 以及其在簡單示例應用程序中的實現。
我們還學習瞭如何配置客户端、為請求添加攔截器以及使用 Hystrix 和 ErrorDecoder 處理錯誤。