1. 概述
在本教程中,我們將描述 Spring Cloud OpenFeign一個用於Spring Boot應用程序的聲明性REST客戶端。
Feign使用可插入的註釋支持更輕鬆地編寫Web服務客戶端,其中包括Feign註釋和JAX-RS註釋。
此外,Spring Cloud還增加了對Spring MVC註釋的支持,並使用了與 Spring Web中使用的相同的 HttpMessageConverters。
並且,使用Feign的一個好處是我們不必編寫任何用於調用服務的代碼,除了接口定義。
2. 依賴性
首先,我們將首先創建一個Spring Boot Web項目,並將spring-cloud-starter-openfeign依賴項添加到我們的 pom.xml 文件中:
<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. 實現客戶端
接下來,我們需要將@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:
Decoder - ResponseEntityDecoder,它包裝SpringDecoder, 用於解碼響應
Encoder - SpringEncoder,用於編碼RequestBody
Logger - Slf4jLogger是Feign使用的默認記錄器
Contract - SpringMvcContract,提供註釋處理
Feign-Builder - 用於構造組件的HystrixFeign.Builder
Client - LoadBalancerFeignClient或默認的Feign客戶端
4.1 自定義Bean配置
如果我們想要自定義一個或多個這些bean,我們可以使用@Configuration類覆蓋它們,然後我們將其添加到FeignClient註釋中:
@FeignClient(value = "jplaceholder",
url = "https://jsonplaceholder.typicode.com/",
configuration = MyClientConfiguration.class)
@Configuration
public class MyClientConfiguration {
@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 使用屬性配置
我們可以使用應用程序屬性來配置Feign客戶端,而不是使用@Configuration類,如此application.yml示例所示:
feign:
client:
config:
default:
connectTimeout: 5000
readTimeout: 5000
loggerLevel: basic
使用此配置,我們將應用程序中每個聲明的客戶端的超時設置爲5秒,並將記錄器級別設置爲基本。
最後,我們可以創建配置,使用default作爲客戶端名稱來配置所有@FeignClient 對象,或者我們可以爲配置聲明feign客戶端名稱:
feign:
client:
config:
jplaceholder:
如果我們同時擁有@Configuration bean和配置屬性,配置屬性將覆蓋@Configuration值。
5. 攔截器
添加攔截器是Feign提供的另一個有用的功能。
對於每個HTTP請求/響應,攔截器可以執行各種隱式任務,從身份驗證到日誌記錄。
因此,在下面的代碼片段中,讓我們聲明一個請求攔截器,爲每個請求添加基本身份驗證:
@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.JSONPlaceHolderInterceptor
6. Hystrix支持
Feign支持Hystrix,所以如果我們啓用它,我們就可以實現回退模式。
使用回退模式,當遠程服務調用失敗而不是生成異常時,服務使用者將執行替代代碼路徑以嘗試通過其他方式執行操作。
爲了實現這一目標,我們需要在屬性文件中啓用Hystrix添加 feign.hystrix.enabled = true。
這允許我們實現在服務失敗時調用的回退方法:
@Component
public class JSONPlaceHolderFallback implements JSONPlaceHolderClient {
@Override
public List<Post> getPosts() {
return Collections.emptyList();
}
@Override
public Post getPostById(Long postId) {
return null;
}
}
爲了讓Feign知道已經提供了回退方法,我們還需要在@FeignClient註釋中設置我們的回退類:
@FeignClient(value = "jplaceholder",
url = "https://jsonplaceholder.typicode.com/",
fallback = JSONPlaceHolderFallback.class)
public interface JSONPlaceHolderClient {
// APIs
}
7.記錄
對於每個Feign客戶端,默認情況下會創建一個記錄器。
要啓用日誌記錄,我們應該使用客戶端接口的包名稱在application.propertie文件中聲明它 :
1
logging.level.com.baeldung.cloud.openfeign.client: DEBUG
或者,如果我們只想爲包中的一個特定客戶端啓用日誌記錄,我們可以使用完整的類名:
1
logging.level.com.baeldung.cloud.openfeign.client.JSONPlaceHolderClient: DEBUG
請注意,Feign日誌記錄僅響應DEBUG級別。
我們可以爲每個客戶端配置的Logger.Level指示記錄多少:
@Configuration
public class ClientConfiguration {
@Bean
Logger.Level feignLoggerLevel() {
return Logger.Level.BASIC;
}
}
有四種日誌記錄級別可供選擇:
NONE - 沒有記錄,這是默認值
BASIC - 僅記錄請求方法,URL和響應狀態
HEADERS - 將基本信息與請求和響應標頭一起記錄
FULL - 記錄請求和響應的正文,標題和元數據
8. 錯誤處理
Feign的默認錯誤處理程序ErrorDecoder.default始終拋出FeignException。
現在,這種行爲並不總是最有用的。因此,要自定義拋出的Exception,我們可以使用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:
@Configuration
public class ClientConfiguration {
@Bean
public ErrorDecoder errorDecoder() {
return new CustomErrorDecoder();
}
}
9. 結論
在本文中,我們在一個簡單的示例應用程序中討論了Spring Cloud OpenFeign及其實現。
此外,我們已經瞭解瞭如何配置客戶端,如何在我們的請求中添加攔截器,以及如何使用Hystrix和ErrorDecoder處理錯誤。
像往常一樣,本教程中顯示的所有代碼示例都可以 在GitHub上獲得。