4.0.6

此專案透過自動配置和綁定到 Spring 環境以及其他 Spring 編程模型慣用語,為 Spring Boot 應用程式提供 OpenFeign 整合。

1. 宣告式 REST 客户端:Feign

Feign 是一個宣告式的 Web 服務客户端。它使編寫 Web 服務客户端變得更容易。要使用 Feign,請創建一個介面並對其進行註解。它具有可插拔的註解支援,包括 Feign 註解和 JAX-RS 註解。Feign 還支援可插拔的編碼器和解碼器。Spring Cloud 添加了對 Spring MVC 註解的支援,以及對使用 Spring Web 中預設使用的相同 HttpMessageConverters 的支援。Spring Cloud 整合了 Eureka、Spring Cloud CircuitBreaker 以及 Spring Cloud LoadBalancer,以便在使用 Feign 時提供負載平衡的 http 客户端。

1.1. 如何引入 Feign

若要在您的專案中引入 Feign,請使用群組 org.springframework.cloud 和 artifact id spring-cloud-starter-openfeign 的 starter。請參閱 Spring Cloud 專案頁面,以瞭解有關使用當前 Spring Cloud Release Train 設定您的建置系統的詳細資訊。

Spring Boot 應用程式範例

@SpringBootApplication
@EnableFeignClients
public class Application {

    public static void main(String[] args) {
        SpringApplication.run(Application.class, args);
    }

}
StoreClient.java
@FeignClient("stores")
public interface StoreClient {
    @RequestMapping(method = RequestMethod.GET, value = "/stores")
    List<Store> getStores();

    @RequestMapping(method = RequestMethod.GET, value = "/stores")
    Page<Store> getStores(Pageable pageable);

    @RequestMapping(method = RequestMethod.POST, value = "/stores/{storeId}", consumes = "application/json")
    Store update(@PathVariable("storeId") Long storeId, Store store);

    @RequestMapping(method = RequestMethod.DELETE, value = "/stores/{storeId:\\d+}")
    void delete(@PathVariable Long storeId);
}

@FeignClient 註解中,字串值(上面的 "stores")是一個任意客户端名稱,用於創建 Spring Cloud LoadBalancer 客户端。您也可以使用 url 屬性(絕對值或僅主機名稱)指定 URL。應用程式上下文中的 bean 名稱是介面的完整限定名稱。若要指定您自己的別名值,您可以使用 @FeignClient 註解的 qualifiers 值。

上面的負載平衡器客户端將希望發現 "stores" 服務的實體位址。如果您的應用程式是 Eureka 客户端,那麼它將在 Eureka 服務註冊表中解析該服務。如果您不想使用 Eureka,您可以使用 SimpleDiscoveryClient 在外部配置中配置伺服器列表。

Spring Cloud OpenFeign 支援 Spring Cloud LoadBalancer 阻塞模式的所有可用功能。您可以在專案文檔中閱讀有關它們的更多資訊。

若要在 @Configuration 註解的類別上使用 @EnableFeignClients 註解,請確保指定客户端的位置,例如:@EnableFeignClients(basePackages = "com.example.clients") 或明確列出它們:@EnableFeignClients(clients = InventoryServiceFeignClient.class)

1.1.1. 屬性解析模式

在創建 Feign 客户端 bean 時,我們會解析透過 @FeignClient 註解傳遞的值。從 4.x 開始,這些值會被積極地解析。對於大多數用例來說,這是一個很好的解決方案,並且它還支援 AOT。

如果您需要延遲解析屬性,請將 spring.cloud.openfeign.lazy-attributes-resolution 屬性值設定為 true

對於 Spring Cloud Contract 測試整合,應使用延遲屬性解析。

1.2. 覆寫 Feign 預設值

Spring Cloud 的 Feign 支援中的核心概念是具名客户端。每個 feign 客户端都是組件集合的一部分,這些組件協同工作以按需聯繫遠端伺服器,並且該集合具有一個名稱,您作為應用程式開發人員可以使用 @FeignClient 註解來指定該名稱。Spring Cloud 使用 FeignClientsConfiguration 為每個具名客户端按需創建一個新的集合作為 ApplicationContext。這包含(除其他外)feign.Decoderfeign.Encoderfeign.Contract。可以使用 @FeignClient 註解的 contextId 屬性來覆寫該集合的名稱。

Spring Cloud 讓您可以透過宣告額外的配置(在 FeignClientsConfiguration 之上)使用 @FeignClient 來完全控制 feign 客户端。範例

@FeignClient(name = "stores", configuration = FooConfiguration.class)
public interface StoreClient {
    //..
}

在這種情況下,客户端由 FeignClientsConfiguration 中已有的組件以及 FooConfiguration 中的任何組件組成(後者將覆寫前者)。

FooConfiguration 不需要使用 @Configuration 進行註解。但是,如果是這種情況,請注意將其從任何 @ComponentScan 中排除,否則該配置將成為指定的 feign.Decoderfeign.Encoderfeign.Contract 等的預設來源。可以透過將其放在與任何 @ComponentScan@SpringBootApplication 分開且不重疊的套件中來避免這種情況,或者可以在 @ComponentScan 中明確排除它。
除了更改 ApplicationContext 集合的名稱外,使用 @FeignClient 註解的 contextId 屬性將覆寫客户端名稱的別名,並且它將用作為該客户端創建的配置 bean 名稱的一部分。
先前,使用 url 屬性不需要 name 屬性。現在需要使用 name

nameurl 屬性中支援佔位符。

@FeignClient(name = "${feign.name}", url = "${feign.url}")
public interface StoreClient {
    //..
}

Spring Cloud OpenFeign 預設為 feign 提供以下 bean (BeanType beanName: ClassName)

  • Decoder feignDecoder: ResponseEntityDecoder (它包裝了 SpringDecoder)

  • Encoder feignEncoder: SpringEncoder

  • Logger feignLogger: Slf4jLogger

  • MicrometerObservationCapability micrometerObservationCapability: 如果 feign-micrometer 在類別路徑上且 ObservationRegistry 可用

  • MicrometerCapability micrometerCapability: 如果 feign-micrometer 在類別路徑上,MeterRegistry 可用且 ObservationRegistry 不可用

  • CachingCapability cachingCapability: 如果使用了 @EnableCaching 註解。可以透過 spring.cloud.openfeign.cache.enabled 停用。

  • Contract feignContract: SpringMvcContract

  • Feign.Builder feignBuilder: FeignCircuitBreaker.Builder

  • Client feignClient: 如果 Spring Cloud LoadBalancer 在類別路徑上,則使用 FeignBlockingLoadBalancerClient。如果它們都不在類別路徑上,則使用預設的 feign 客户端。

spring-cloud-starter-openfeign 支援 spring-cloud-starter-loadbalancer。但是,由於它是一個可選的依賴項,如果您想使用它,則需要確保已將其添加到您的專案中。

若要使用 OkHttpClient 後端的 Feign 客户端,請確保 OKHttpClient 在您的類別路徑上,並將 spring.cloud.openfeign.okhttp.enabled 設定為 true

當涉及到 Apache HttpClient 5 後端的 Feign 客户端時,只需確保 HttpClient 5 在類別路徑上即可,但您仍然可以透過將 spring.cloud.openfeign.httpclient.hc5.enabled 設定為 false 來停用其用於 Feign 客户端。您可以透過在使用 Apache HC5 時提供 org.apache.hc.client5.http.impl.classic.CloseableHttpClient 的 bean 來客製化 HTTP 客户端。

您可以透過在 spring.cloud.openfeign.httpclient.xxx 屬性中設定值來進一步客製化 http 客户端。僅以 httpclient 為前綴的那些屬性將適用於所有客户端,以 httpclient.hc5 為前綴的那些屬性適用於 Apache HttpClient 5,以 httpclient.okhttp 為前綴的那些屬性適用於 OkHttpClient。您可以在附錄中找到您可以客製化的完整屬性列表。

從 Spring Cloud OpenFeign 4 開始,不再支援 Feign Apache HttpClient 4。我們建議改用 Apache HttpClient 5。

Spring Cloud OpenFeign 預設為 feign 提供以下 bean,但仍會從應用程式上下文中查找這些類型的 bean 以創建 feign 客户端

  • Logger.Level

  • Retryer

  • ErrorDecoder

  • Request.Options

  • Collection<RequestInterceptor>

  • SetterFactory

  • QueryMapEncoder

  • Capability (預設提供 MicrometerObservationCapabilityCachingCapability)

預設情況下,會創建類型為 RetryerRetryer.NEVER_RETRY bean,這將停用重試。請注意,此重試行為與 Feign 預設行為不同,在 Feign 預設行為中,它會自動重試 IOExceptions,將它們視為瞬時網路相關異常,以及從 ErrorDecoder 拋出的任何 RetryableException。

創建其中一種型別的 bean 並將其放置在 @FeignClient 配置中(例如上面的 FooConfiguration)允許您覆寫每個描述的 bean。範例

@Configuration
public class FooConfiguration {
    @Bean
    public Contract feignContract() {
        return new feign.Contract.Default();
    }

    @Bean
    public BasicAuthRequestInterceptor basicAuthRequestInterceptor() {
        return new BasicAuthRequestInterceptor("user", "password");
    }
}

這會將 SpringMvcContract 替換為 feign.Contract.Default,並將 RequestInterceptor 添加到 RequestInterceptor 集合中。

也可以使用配置屬性配置 @FeignClient

application.yml

spring:
    cloud:
        openfeign:
            client:
                config:
                    feignName:
                        url: http://remote-service.com
                        connectTimeout: 5000
                        readTimeout: 5000
                        loggerLevel: full
                        errorDecoder: com.example.SimpleErrorDecoder
                        retryer: com.example.SimpleRetryer
                        defaultQueryParameters:
                            query: queryValue
                        defaultRequestHeaders:
                            header: headerValue
                        requestInterceptors:
                            - com.example.FooRequestInterceptor
                            - com.example.BarRequestInterceptor
                        responseInterceptor: com.example.BazResponseInterceptor
                        dismiss404: false
                        encoder: com.example.SimpleEncoder
                        decoder: com.example.SimpleDecoder
                        contract: com.example.SimpleContract
                        capabilities:
                            - com.example.FooCapability
                            - com.example.BarCapability
                        queryMapEncoder: com.example.SimpleQueryMapEncoder
                        micrometer.enabled: false

在此範例中,feignName 指的是 @FeignClient value,它也與 @FeignClient name@FeignClient contextId 互為別名。在負載平衡場景中,它也對應於伺服器應用程式的 serviceId,該伺服器應用程式將用於檢索實例。解碼器、重試器和其他指定的類別必須在 Spring 上下文中具有 bean 或具有預設建構子。

預設配置可以在 @EnableFeignClients 屬性 defaultConfiguration 中指定,方式與上述描述類似。不同之處在於,此配置將應用於所有 feign 客户端。

如果您喜歡使用配置屬性來配置所有 @FeignClient,則可以使用 default feign 名稱創建配置屬性。

您可以使用 spring.cloud.openfeign.client.config.feignName.defaultQueryParametersspring.cloud.openfeign.client.config.feignName.defaultRequestHeaders 來指定查詢參數和標頭,這些參數和標頭將與名為 feignName 的客户端的每個請求一起發送。

application.yml

spring:
    cloud:
        openfeign:
            client:
                config:
                    default:
                        connectTimeout: 5000
                        readTimeout: 5000
                        loggerLevel: basic

如果我們同時創建 @Configuration bean 和配置屬性,則配置屬性將獲勝。它將覆寫 @Configuration 值。但是,如果您想將優先順序更改為 @Configuration,則可以將 spring.cloud.openfeign.client.default-to-properties 更改為 false

如果我們想要創建多個具有相同名稱或 url 的 feign 客户端,以便它們指向同一伺服器,但每個客户端具有不同的自訂配置,那麼我們必須使用 @FeignClientcontextId 屬性,以避免這些配置 bean 的名稱衝突。

@FeignClient(contextId = "fooClient", name = "stores", configuration = FooConfiguration.class)
public interface FooClient {
    //..
}
@FeignClient(contextId = "barClient", name = "stores", configuration = BarConfiguration.class)
public interface BarClient {
    //..
}

也可以配置 FeignClient 不繼承父上下文中的 bean。您可以透過覆寫 FeignClientConfigurer bean 中的 inheritParentConfiguration() 以返回 false 來實現此目的

@Configuration
public class CustomConfiguration {
    @Bean
    public FeignClientConfigurer feignClientConfigurer() {
        return new FeignClientConfigurer() {
            @Override
            public boolean inheritParentConfiguration() {
                 return false;
            }
        };
    }
}
預設情況下,Feign 客户端不編碼斜線 / 字元。您可以透過將 spring.cloud.openfeign.client.decodeSlash 的值設定為 false 來更改此行為。

1.2.1. SpringEncoder 配置

在我們提供的 SpringEncoder 中,我們為二進制內容類型設定 null 字元集,為所有其他類型設定 UTF-8

您可以修改此行為,方法是透過將 spring.cloud.openfeign.encoder.charset-from-content-type 的值設定為 true,從 Content-Type 標頭字元集派生字元集。

1.3. 超時處理

我們可以在預設客户端和具名客户端上配置超時。OpenFeign 使用兩個超時參數

  • connectTimeout 可防止由於伺服器處理時間過長而阻塞呼叫者。

  • readTimeout 從建立連線時開始應用,並在返回響應花費時間過長時觸發。

如果伺服器未執行或不可用,則封包會導致連線被拒絕。通訊以錯誤訊息或回退結束。如果 connectTimeout 設定得非常低,則可能會在 connectTimeout 之前 發生這種情況。執行查找和接收此類封包所花費的時間會導致此延遲的大部分。它可能會根據涉及 DNS 查找的遠端主機而發生變化。

1.4. 手動創建 Feign 客户端

在某些情況下,可能需要以使用上述方法無法實現的方式來自訂您的 Feign 客户端。在這種情況下,您可以使用 Feign Builder API 創建客户端。以下範例創建了兩個具有相同介面的 Feign 客户端,但為每個客户端配置了單獨的請求攔截器。

@Import(FeignClientsConfiguration.class)
class FooController {

    private FooClient fooClient;

    private FooClient adminClient;

    @Autowired
    public FooController(Client client, Encoder encoder, Decoder decoder, Contract contract, MicrometerObservationCapability micrometerObservationCapability) {
        this.fooClient = Feign.builder().client(client)
                .encoder(encoder)
                .decoder(decoder)
                .contract(contract)
                .addCapability(micrometerObservationCapability)
                .requestInterceptor(new BasicAuthRequestInterceptor("user", "user"))
                .target(FooClient.class, "https://PROD-SVC");

        this.adminClient = Feign.builder().client(client)
                .encoder(encoder)
                .decoder(decoder)
                .contract(contract)
                .addCapability(micrometerObservationCapability)
                .requestInterceptor(new BasicAuthRequestInterceptor("admin", "admin"))
                .target(FooClient.class, "https://PROD-SVC");
    }
}
在上面的範例中,FeignClientsConfiguration.class 是 Spring Cloud OpenFeign 提供的預設配置。
PROD-SVC 是客户端將向其發出請求的服務名稱。
Feign Contract 物件定義了介面上哪些註解和值是有效的。自動裝配的 Contract bean 提供了對 SpringMVC 註解的支援,而不是預設的 Feign 原生註解。

您也可以使用 Builder 來配置 FeignClient 不繼承父上下文中的 bean。您可以透過在 Builder 上呼叫 inheritParentContext(false) 來實現此目的。

1.5. Feign Spring Cloud 斷路器支援

如果 Spring Cloud CircuitBreaker 在類別路徑上且 spring.cloud.openfeign.circuitbreaker.enabled=true,Feign 將使用斷路器包裝所有方法。

若要在每個客户端的基礎上停用 Spring Cloud CircuitBreaker 支援,請創建一個具有 "prototype" 範圍的普通 Feign.Builder,例如

@Configuration
public class FooConfiguration {
    @Bean
    @Scope("prototype")
    public Feign.Builder feignBuilder() {
        return Feign.builder();
    }
}

斷路器名稱遵循此模式 <feignClientClassName>#<calledMethod>(<parameterTypes>)。當呼叫具有 FooClient 介面的 @FeignClient 且呼叫的介面方法沒有參數時,斷路器名稱將為 FooClient#bar()

從 2020.0.2 開始,斷路器名稱模式已從 <feignClientName>_<calledMethod> 更改。使用 2020.0.4 中引入的 CircuitBreakerNameResolver,斷路器名稱可以保留舊模式。

透過提供 CircuitBreakerNameResolver 的 bean,您可以更改斷路器名稱模式。

@Configuration
public class FooConfiguration {
    @Bean
    public CircuitBreakerNameResolver circuitBreakerNameResolver() {
        return (String feignClientName, Target<?> target, Method method) -> feignClientName + "_" + method.getName();
    }
}

若要啟用 Spring Cloud CircuitBreaker 群組,請將 spring.cloud.openfeign.circuitbreaker.group.enabled 屬性設定為 true(預設為 false)。

1.6. 使用配置屬性配置斷路器

您可以透過配置屬性配置 CircuitBreakers。

例如,如果您有此 Feign 客户端

@FeignClient(url = "http://localhost:8080")
public interface DemoClient {

    @GetMapping("demo")
    String getDemo();
}

您可以透過執行以下操作使用配置屬性來配置它

spring:
  cloud:
    openfeign:
      circuitbreaker:
        enabled: true
        alphanumeric-ids:
          enabled: true
resilience4j:
  circuitbreaker:
    instances:
      DemoClientgetDemo:
        minimumNumberOfCalls: 69
  timelimiter:
    instances:
      DemoClientgetDemo:
        timeoutDuration: 10s
如果您想切換回 Spring Cloud 2022.0.0 之前使用的斷路器名稱,您可以將 spring.cloud.openfeign.circuitbreaker.alphanumeric-ids.enabled 設定為 false

1.7. Feign Spring Cloud 斷路器回退

Spring Cloud CircuitBreaker 支援回退的概念:當斷路器打開或發生錯誤時執行的預設程式碼路徑。若要為給定的 @FeignClient 啟用回退,請將 fallback 屬性設定為實作回退的類別名稱。您還需要將您的實作宣告為 Spring bean。

@FeignClient(name = "test", url = "http://localhost:${server.port}/", fallback = Fallback.class)
protected interface TestClient {

    @RequestMapping(method = RequestMethod.GET, value = "/hello")
    Hello getHello();

    @RequestMapping(method = RequestMethod.GET, value = "/hellonotfound")
    String getException();

}

@Component
static class Fallback implements TestClient {

    @Override
    public Hello getHello() {
        throw new NoFallbackAvailableException("Boom!", new RuntimeException());
    }

    @Override
    public String getException() {
        return "Fixed response";
    }

}

如果需要存取導致回退觸發的原因,可以使用 @FeignClient 內的 fallbackFactory 屬性。

@FeignClient(name = "testClientWithFactory", url = "http://localhost:${server.port}/",
            fallbackFactory = TestFallbackFactory.class)
protected interface TestClientWithFactory {

    @RequestMapping(method = RequestMethod.GET, value = "/hello")
    Hello getHello();

    @RequestMapping(method = RequestMethod.GET, value = "/hellonotfound")
    String getException();

}

@Component
static class TestFallbackFactory implements FallbackFactory<FallbackWithFactory> {

    @Override
    public FallbackWithFactory create(Throwable cause) {
        return new FallbackWithFactory();
    }

}

static class FallbackWithFactory implements TestClientWithFactory {

    @Override
    public Hello getHello() {
        throw new NoFallbackAvailableException("Boom!", new RuntimeException());
    }

    @Override
    public String getException() {
        return "Fixed response";
    }

}

1.8. Feign 和 @Primary

將 Feign 與 Spring Cloud CircuitBreaker 回退一起使用時,ApplicationContext 中存在多個相同類型的 bean。這將導致 @Autowired 無法運作,因為沒有完全一個 bean,也沒有一個標記為 primary。為了解決這個問題,Spring Cloud OpenFeign 將所有 Feign 實例標記為 @Primary,因此 Spring Framework 將知道要注入哪個 bean。在某些情況下,這可能是不希望的。若要關閉此行為,請將 @FeignClientprimary 屬性設定為 false。

@FeignClient(name = "hello", primary = false)
public interface HelloClient {
    // methods here
}

1.9. Feign 繼承支援

Feign 透過單一繼承介面支援樣板程式碼 API。這允許將常見操作分組到方便的基本介面中。

UserService.java
public interface UserService {

    @RequestMapping(method = RequestMethod.GET, value ="/users/{id}")
    User getUser(@PathVariable("id") long id);
}
UserResource.java
@RestController
public class UserResource implements UserService {

}
UserClient.java
package project.user;

@FeignClient("users")
public interface UserClient extends UserService {

}
@FeignClient 介面不應在伺服器和客户端之間共享,並且不再支援在類別層級使用 @RequestMapping 註解 @FeignClient 介面。

1.10. Feign 請求/響應壓縮

您可以考慮為您的 Feign 請求啟用請求或響應 GZIP 壓縮。您可以透過啟用以下屬性之一來實現此目的

spring.cloud.openfeign.compression.request.enabled=true
spring.cloud.openfeign.compression.response.enabled=true

Feign 請求壓縮為您提供類似於您可以為 Web 伺服器設定的設定

spring.cloud.openfeign.compression.request.enabled=true
spring.cloud.openfeign.compression.request.mime-types=text/xml,application/xml,application/json
spring.cloud.openfeign.compression.request.min-request-size=2048

這些屬性允許您有選擇地處理壓縮的媒體類型和最小請求閾值長度。

由於 OkHttpClient 使用「透明」壓縮,因此如果存在 content-encodingaccept-encoding 標頭,則會停用該壓縮,如果 feign.okhttp.OkHttpClient 存在於類別路徑上且 spring.cloud.openfeign.okhttp.enabled 設定為 true,我們將不會啟用壓縮。

1.11. Feign 日誌記錄

為創建的每個 Feign 客户端創建一個記錄器。預設情況下,記錄器的名稱是用於創建 Feign 客户端的介面的完整類別名稱。Feign 日誌記錄僅響應 DEBUG 層級。

application.yml
logging.level.project.user.UserClient: DEBUG

您可以為每個客户端配置的 Logger.Level 物件告訴 Feign 要記錄多少內容。選項包括

  • NONE,不記錄 (預設值)。

  • BASIC,僅記錄請求方法和 URL 以及響應狀態碼和執行時間。

  • HEADERS,記錄基本資訊以及請求和響應標頭。

  • FULL,記錄請求和響應的標頭、正文和元數據。

例如,以下程式碼會將 Logger.Level 設定為 FULL

@Configuration
public class FooConfiguration {
    @Bean
    Logger.Level feignLoggerLevel() {
        return Logger.Level.FULL;
    }
}

1.12. Feign 功能支援

Feign 功能公開了核心 Feign 組件,以便可以修改這些組件。例如,功能可以取得 Client裝飾它,然後將裝飾後的實例返回給 Feign。對 Micrometer 的支援是這方面的一個很好的真實範例。請參閱 Micrometer 支援

創建一個或多個 Capability bean 並將它們放在 @FeignClient 配置中,您可以註冊它們並修改相關客户端的行為。

@Configuration
public class FooConfiguration {
    @Bean
    Capability customCapability() {
        return new CustomCapability();
    }
}

1.13. Micrometer 支援

如果以下所有條件都為真,則會創建並註冊 MicrometerObservationCapability bean,以便您的 Feign 客户端可以被 Micrometer 觀察

  • feign-micrometer 在類別路徑上

  • ObservationRegistry bean 可用

  • feign micrometer 屬性設定為 true(預設情況下)

    • spring.cloud.openfeign.micrometer.enabled=true(對於所有客户端)

    • spring.cloud.openfeign.client.config.feignName.micrometer.enabled=true(對於單個客户端)

如果您的應用程式已在使用 Micrometer,則啟用此功能就像將 feign-micrometer 放入您的類別路徑一樣簡單。

您也可以透過以下任一方式停用該功能

  • 從您的類別路徑中排除 feign-micrometer

  • 將 feign micrometer 屬性之一設定為 false

    • spring.cloud.openfeign.micrometer.enabled=false

    • spring.cloud.openfeign.client.config.feignName.micrometer.enabled=false

spring.cloud.openfeign.micrometer.enabled=false 停用所有 Feign 客户端的 Micrometer 支援,而與客户端層級標誌的值無關:spring.cloud.openfeign.client.config.feignName.micrometer.enabled。如果您想為每個客户端啟用或停用 Micrometer 支援,請勿設定 spring.cloud.openfeign.micrometer.enabled,而應使用 spring.cloud.openfeign.client.config.feignName.micrometer.enabled

您也可以透過註冊您自己的 bean 來客製化 MicrometerObservationCapability

@Configuration
public class FooConfiguration {
    @Bean
    public MicrometerObservationCapability micrometerObservationCapability(ObservationRegistry registry) {
        return new MicrometerObservationCapability(registry);
    }
}

仍然可以將 MicrometerCapability 與 Feign (僅指標支援) 一起使用,您需要停用 Micrometer 支援 (spring.cloud.openfeign.micrometer.enabled=false) 並創建 MicrometerCapability bean

@Configuration
public class FooConfiguration {
    @Bean
    public MicrometerCapability micrometerCapability(MeterRegistry meterRegistry) {
        return new MicrometerCapability(meterRegistry);
    }
}

1.14. Feign 快取

如果使用了 @EnableCaching 註解,則會創建並註冊 CachingCapability bean,以便您的 Feign 客户端識別其介面上的 @Cache* 註解

public interface DemoClient {

    @GetMapping("/demo/{filterParam}")
    @Cacheable(cacheNames = "demo-cache", key = "#keyParam")
    String demoEndpoint(String keyParam, @PathVariable String filterParam);
}

您也可以透過屬性 spring.cloud.openfeign.cache.enabled=false 停用該功能。

1.15. Feign @QueryMap 支援

Spring Cloud OpenFeign 提供了等效的 @SpringQueryMap 註解,該註解用於將 POJO 或 Map 參數註解為查詢參數映射。

例如,Params 類別定義了參數 param1param2

// Params.java
public class Params {
    private String param1;
    private String param2;

    // [Getters and setters omitted for brevity]
}

以下 feign 客户端透過使用 @SpringQueryMap 註解來使用 Params 類別

@FeignClient("demo")
public interface DemoTemplate {

    @GetMapping(path = "/demo")
    String demoEndpoint(@SpringQueryMap Params params);
}

如果您需要對產生的查詢參數映射進行更多控制,則可以實作自訂的 QueryMapEncoder bean。

1.16. HATEOAS 支援

Spring 提供了一些 API 來創建遵循 HATEOAS 原則的 REST 表示形式,Spring HateoasSpring Data REST

如果您的專案使用 org.springframework.boot:spring-boot-starter-hateoas starter 或 org.springframework.boot:spring-boot-starter-data-rest starter,則預設情況下會啟用 Feign HATEOAS 支援。

啟用 HATEOAS 支援後,允許 Feign 客户端序列化和反序列化 HATEOAS 表示模型:EntityModelCollectionModelPagedModel

@FeignClient("demo")
public interface DemoTemplate {

    @GetMapping(path = "/stores")
    CollectionModel<Store> getStores();
}

1.17. Spring @MatrixVariable 支援

Spring Cloud OpenFeign 提供了對 Spring @MatrixVariable 註解的支援。

如果將映射作為方法參數傳遞,則透過使用 = 連接映射中的鍵值對來創建 @MatrixVariable 路徑段。

如果傳遞了不同的物件,則使用 = 連接 @MatrixVariable 註解中提供的 name(如果已定義)或註解的變數名稱以及提供的方法參數。

重要提示

即使在伺服器端,Spring 不要求用戶將路徑段佔位符命名為與矩陣變數名稱相同,但由於在客户端會過於模糊,因此 Spring Cloud OpenFeign 要求您添加路徑段佔位符,其名稱與 @MatrixVariable 註解中提供的 name(如果已定義)或註解的變數名稱相符。

例如

@GetMapping("/objects/links/{matrixVars}")
Map<String, List<String>> getObjects(@MatrixVariable Map<String, List<String>> matrixVars);

請注意,變數名稱和路徑段佔位符都稱為 matrixVars

@FeignClient("demo")
public interface DemoTemplate {

    @GetMapping(path = "/stores")
    CollectionModel<Store> getStores();
}

1.18. Feign CollectionFormat 支援

我們透過提供 @CollectionFormat 註解來支援 feign.CollectionFormat。您可以透過傳遞所需的 feign.CollectionFormat 作為註解值,使用它來註解 Feign 客户端方法(或整個類別以影響所有方法)。

在以下範例中,使用了 CSV 格式而不是預設的 EXPLODED 來處理該方法。

@FeignClient(name = "demo")
protected interface DemoFeignClient {

    @CollectionFormat(feign.CollectionFormat.CSV)
    @GetMapping(path = "/test")
    ResponseEntity performRequest(String test);

}

1.19. 反應式支援

由於 OpenFeign 專案 目前不支援反應式客户端,例如 Spring WebClient,Spring Cloud OpenFeign 也不支援。一旦核心專案中提供支援,我們將在此處添加對它的支援。

在完成之前,我們建議使用 feign-reactive 來支援 Spring WebClient。

1.19.1. 早期初始化錯誤

我們不鼓勵在應用程式生命週期的早期階段(在處理配置和初始化 bean 時)使用 Feign 客户端。不支援在 bean 初始化期間使用客户端。

同樣,根據您使用 Feign 客户端的方式,您可能會在啟動應用程式時看到初始化錯誤。若要解決此問題,您可以在自動裝配客户端時使用 ObjectProvider

@Autowired
ObjectProvider<TestFeignClient> testFeignClient;

1.20. Spring Data 支援

如果 Jackson Databind 和 Spring Data Commons 在類別路徑上,則會自動添加 org.springframework.data.domain.Pageorg.springframework.data.domain.Sort 的轉換器。

若要停用此行為,請設定

spring.cloud.openfeign.autoconfiguration.jackson.enabled=false

請參閱 org.springframework.cloud.openfeign.FeignAutoConfiguration.FeignJacksonConfiguration 以瞭解詳細資訊。

1.21. Spring @RefreshScope 支援

如果啟用了 Feign 客户端刷新,則每個 Feign 客户端都使用以下內容創建

  • feign.Request.Options 作為刷新範圍的 bean。這表示可以針對任何 Feign 客户端實例刷新 connectTimeoutreadTimeout 等屬性。

  • 一個包裹在 org.springframework.cloud.openfeign.RefreshableUrl 下的 url。這表示 Feign 客户端的 URL(如果使用 spring.cloud.openfeign.client.config.{feignName}.url 屬性定義),可以針對任何 Feign 客户端實例進行刷新。

您可以透過 POST /actuator/refresh 刷新這些屬性。

預設情況下,Feign 客户端中的刷新行為已停用。使用以下屬性來啟用刷新行為

spring.cloud.openfeign.client.refresh-enabled=true
請勿使用 @RefreshScope 註解來註解 @FeignClient 介面。

1.22. OAuth2 支援

可以透過將 spring-boot-starter-oauth2-client 依賴項添加到您的專案並設定以下標誌來啟用 OAuth2 支援

spring.cloud.openfeign.oauth2.enabled=true

當標誌設定為 true 且 oauth2 客户端上下文資源詳細資訊存在時,將創建 OAuth2AccessTokenInterceptor 類別的 bean。在每個請求之前,攔截器都會解析所需的存取令牌並將其作為標頭包含在內。OAuth2AccessTokenInterceptor 使用 OAuth2AuthorizedClientManager 來取得持有 OAuth2AccessTokenOAuth2AuthorizedClient。如果用戶使用 spring.cloud.openfeign.oauth2.clientRegistrationId 屬性指定了 OAuth2 clientRegistrationId,則將使用它來檢索令牌。如果未檢索到令牌或未指定 clientRegistrationId,則將使用從 url 主機段檢索的 serviceId

提示

使用 serviceId 作為 OAuth2 client registrationId 對於負載平衡的 Feign client 來說很方便。對於非負載平衡的 client,基於屬性的 clientRegistrationId 是一個合適的方法。

提示

如果您不想使用 OAuth2AuthorizedClientManager 的預設設定,您可以直接在您的配置中實例化此類型的 bean。

1.23. 轉換負載平衡的 HTTP 請求

您可以使用選定的 ServiceInstance 來轉換負載平衡的 HTTP 請求。

對於 Request,您需要實作並定義 LoadBalancerFeignRequestTransformer,如下所示

@Bean
public LoadBalancerFeignRequestTransformer transformer() {
    return new LoadBalancerFeignRequestTransformer() {

        @Override
        public Request transformRequest(Request request, ServiceInstance instance) {
            Map<String, Collection<String>> headers = new HashMap<>(request.headers());
            headers.put("X-ServiceId", Collections.singletonList(instance.getServiceId()));
            headers.put("X-InstanceId", Collections.singletonList(instance.getInstanceId()));
            return Request.create(request.httpMethod(), request.url(), headers, request.body(), request.charset(),
                    request.requestTemplate());
        }
    };
}

如果定義了多個轉換器,它們會按照 bean 定義的順序套用。或者,您可以使用 LoadBalancerFeignRequestTransformer.DEFAULT_ORDER 來指定順序。

1.24. X-Forwarded Headers 支援

可以透過設定以下標誌來啟用 X-Forwarded-HostX-Forwarded-Proto 支援

spring.cloud.loadbalancer.x-forwarded.enabled=true

1.25. 提供 URL 給 Feign Client 的支援方式

您可以使用以下任何一種方式來提供 URL 給 Feign client

案例 範例 詳細資訊

URL 在 @FeignClient 註解中提供。

@FeignClient(name="testClient", url="http://localhost:8081")

URL 從註解的 url 屬性解析,不使用負載平衡。

URL 在 @FeignClient 註解和配置屬性中提供。

@FeignClient(name="testClient", url="http://localhost:8081") 以及在 application.yml 中定義的屬性,例如 spring.cloud.openfeign.client.config.testClient.url=http://localhost:8081

URL 從註解的 url 屬性解析,不使用負載平衡。配置屬性中提供的 URL 保持未使用狀態。

URL 未在 @FeignClient 註解中提供,但在配置屬性中提供。

@FeignClient(name="testClient") 以及在 application.yml 中定義的屬性,例如 spring.cloud.openfeign.client.config.testClient.url=http://localhost:8081

URL 從配置屬性解析,不使用負載平衡。 如果 spring.cloud.openfeign.client.refresh-enabled=true,則配置屬性中定義的 URL 可以按照 Spring RefreshScope 支援 中所述的方式刷新。

URL 未在 @FeignClient 註解中提供,也未在配置屬性中提供。

@FeignClient(name="testClient")

URL 從註解的 name 屬性解析,使用負載平衡。

1.26. AOT 和 Native Image 支援

Spring Cloud OpenFeign 支援 Spring AOT 轉換和 native image,但是,僅在禁用刷新模式、禁用 Feign client 刷新(預設設定)和禁用 lazy @FeignClient 屬性解析(預設設定)的情況下。

如果您想在 AOT 或 native image 模式下運行 Spring Cloud OpenFeign client,請確保將 spring.cloud.refresh.enabled 設定為 false
如果您想在 AOT 或 native image 模式下運行 Spring Cloud OpenFeign client,請確保 spring.cloud.openfeign.client.refresh-enabled 未設定為 true
如果您想在 AOT 或 native image 模式下運行 Spring Cloud OpenFeign client,請確保 spring.cloud.openfeign.lazy-attributes-resolution 未設定為 true
然而,如果您透過屬性設定 url 值,則可以透過使用 -Dspring.cloud.openfeign.client.config.[clientId].url=[url] 標誌運行 image 來覆寫 @FeignClienturl 值。為了啟用覆寫,還必須在建置時透過屬性而不是 @FeignClient 屬性設定 url 值。

2. 配置屬性

若要查看所有與 Spring Cloud OpenFeign 相關的配置屬性列表,請查看 附錄頁面