Spring Cloud OpenFeign 功能
宣告式 REST Client: Feign
Feign 是一個宣告式的網路服務客戶端。它讓撰寫網路服務客戶端變得更容易。要使用 Feign,請建立一個介面並加上註解。它具有可插拔的註解支援,包括 Feign 註解和 JAX-RS 註解。Feign 也支援可插拔的編碼器和解碼器。Spring Cloud 新增了對 Spring MVC 註解的支援,以及使用與 Spring Web 中預設相同的 HttpMessageConverters
。Spring Cloud 整合了 Eureka、Spring Cloud CircuitBreaker 以及 Spring Cloud LoadBalancer,在使用 Feign 時提供負載平衡的 http 客戶端。
如何包含 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);
}
}
@FeignClient("stores")
public interface StoreClient {
@RequestMapping(method = RequestMethod.GET, value = "/stores")
List<Store> getStores();
@GetMapping("/stores")
Page<Store> getStores(Pageable pageable);
@PostMapping(value = "/stores/{storeId}", consumes = "application/json",
params = "mode=upsert")
Store update(@PathVariable("storeId") Long storeId, Store store);
@DeleteMapping("/stores/{storeId:\\d+}")
void delete(@PathVariable Long storeId);
}
在 @FeignClient
註解中,字串值(上面的 "stores")是任意的客戶端名稱,用於建立 Spring Cloud LoadBalancer client。您也可以使用 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) 。 |
由於 FactoryBean 物件可能會在應該發生的初始內容重新整理之前被實例化,而且 Spring Cloud OpenFeign Clients 的實例化會觸發內容重新整理,因此它們不應在 FactoryBean 類別中宣告。 |
覆寫 Feign 預設值
Spring Cloud 的 Feign 支援中的核心概念是具名客戶端。每個 feign 客戶端都是組件集合的一部分,這些組件協同工作以按需聯絡遠端伺服器,並且該集合有一個名稱,您作為應用程式開發人員使用 @FeignClient
註解為其命名。Spring Cloud 使用 FeignClientsConfiguration
為每個具名客戶端按需建立一個新的集合作為 ApplicationContext
。這包含(除其他外)feign.Decoder
、feign.Encoder
和 feign.Contract
。可以使用 @FeignClient
註解的 contextId
屬性來覆寫該集合的名稱。
Spring Cloud 讓您透過宣告額外組態(在 FeignClientsConfiguration
之上)並使用 @FeignClient
來完全控制 feign 客戶端。範例
@FeignClient(name = "stores", configuration = FooConfiguration.class)
public interface StoreClient {
//..
}
在這種情況下,客戶端由 FeignClientsConfiguration
中已有的組件以及 FooConfiguration
中的任何組件組成(後者將覆寫前者)。
FooConfiguration 不需要使用 @Configuration 進行註解。但是,如果它是,請注意將其從任何 @ComponentScan 中排除,否則該組態將成為指定時 feign.Decoder 、feign.Encoder 、feign.Contract 等的預設來源。這可以透過將其放在與任何 @ComponentScan 或 @SpringBootApplication 分開且不重疊的套件中來避免,或者可以在 @ComponentScan 中明確排除它。 |
除了變更 ApplicationContext 集合的名稱外,使用 @FeignClient 註解的 contextId 屬性也會覆寫客戶端名稱的別名,並將其用作為該客戶端建立的組態 bean 的名稱的一部分。 |
先前,使用 url 屬性不需要 name 屬性。現在需要使用 name 。 |
name
和 url
屬性中支援佔位符。
@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 客戶端和 Http2Client Feign 客戶端,請確保您想要使用的客戶端在類別路徑上,並將 spring.cloud.openfeign.okhttp.enabled
或 spring.cloud.openfeign.http2client.enabled
分別設定為 true
。
當涉及到 Apache HttpClient 5 支援的 Feign 客戶端時,只需確保 HttpClient 5 在類別路徑上就足夠了,但您仍然可以透過將 spring.cloud.openfeign.httpclient.hc5.enabled
設定為 false
來停用其用於 Feign Clients。您可以透過在使用 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,以 httpclient.http2
為前綴的那些屬性適用於 Http2Client。您可以在附錄中找到您可以客製化的屬性的完整清單。如果您無法透過使用屬性來組態 Apache HttpClient 5,則有一個 HttpClientBuilderCustomizer
介面用於程式化組態。
從 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
(預設提供MicrometerObservationCapability
和CachingCapability
)
預設情況下,會建立類型為 Retryer
的 Retryer.NEVER_RETRY
的 bean,這將停用重試。請注意,此重試行為與 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.defaultQueryParameters
和 spring.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 客戶端,以便它們指向相同的伺服器,但每個客戶端都具有不同的自訂組態,那麼我們必須使用 @FeignClient
的 contextId
屬性,以避免這些組態 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 來變更此行為。 |
逾時處理
我們可以在預設客戶端和具名客戶端上組態逾時。OpenFeign 使用兩個逾時參數
-
connectTimeout
可防止呼叫端因伺服器處理時間過長而封鎖。 -
readTimeout
從連線建立時開始應用,並在傳回回應花費時間過長時觸發。
如果伺服器未執行或不可用,則封包會導致連線被拒絕。通訊以錯誤訊息或回退結束。如果 connectTimeout 設定得非常低,則可能會在之前發生這種情況。執行查找和接收此類封包所花費的時間會導致此延遲的很大一部分。它可能會根據涉及 DNS 查找的遠端主機而變化。 |
手動建立 Feign 客戶端
在某些情況下,可能需要以使用上述方法不可能的方式自訂您的 Feign Clients。在這種情況下,您可以使用 Feign Builder API 建立 Clients。以下範例建立兩個具有相同介面的 Feign Clients,但每個都使用單獨的請求攔截器進行組態。
@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 是 Clients 將向其發出請求的服務的名稱。 |
Feign Contract 物件定義了介面上哪些註解和值是有效的。自動裝配的 Contract bean 提供了對 SpringMVC 註解的支援,而不是預設的 Feign 原生註解。 |
您也可以使用 Builder
來組態 FeignClient 不繼承父內容中的 bean。您可以透過在 Builder
上覆寫呼叫 inheritParentContext(false)
來執行此操作。
Feign Spring Cloud CircuitBreaker 支援
如果 Spring Cloud CircuitBreaker 在類別路徑上且 spring.cloud.openfeign.circuitbreaker.enabled=true
,則 Feign 將使用斷路器包裝所有方法。
若要針對每個客戶端停用 Spring Cloud CircuitBreaker 支援,請使用 "prototype" 範圍建立 vanilla Feign.Builder
,例如
@Configuration
public class FooConfiguration {
@Bean
@Scope("prototype")
public Feign.Builder feignBuilder() {
return Feign.builder();
}
}
斷路器名稱遵循此模式 <feignClientClassName>#<calledMethod>(<parameterTypes>)
。當使用 FooClient
介面呼叫 @FeignClient
且呼叫的介面方法沒有參數時,bar
則斷路器名稱將為 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
)。
使用組態屬性組態斷路器
您可以透過組態屬性組態斷路器。
例如,如果您有此 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 。 |
Feign Spring Cloud CircuitBreaker 回退
Spring Cloud CircuitBreaker 支援回退的概念:當斷路器開啟或發生錯誤時執行的預設程式碼路徑。若要為給定的 @FeignClient
啟用回退,請將 fallback
屬性設定為實作回退的類別名稱。您還需要將您的實作宣告為 Spring bean。
@FeignClient(name = "test", url = "http://localhost:${server.port}/", fallback = Fallback.class)
protected interface TestClient {
@GetMapping("/hello")
Hello getHello();
@GetMapping("/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 {
@GetMapping("/hello")
Hello getHello();
@GetMapping("/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";
}
}
Feign 和 @Primary
將 Feign 與 Spring Cloud CircuitBreaker 回退一起使用時,ApplicationContext
中有多個相同類型的 bean。這將導致 @Autowired
無法運作,因為沒有正好一個 bean,或一個標記為 primary 的 bean。為了解決這個問題,Spring Cloud OpenFeign 將所有 Feign 實例標記為 @Primary
,因此 Spring Framework 將知道要注入哪個 bean。在某些情況下,這可能不是理想的。若要關閉此行為,請將 @FeignClient
的 primary
屬性設定為 false。
@FeignClient(name = "hello", primary = false)
public interface HelloClient {
// methods here
}
Feign 繼承支援
Feign 透過單一繼承介面支援樣板 api。這允許將常見操作分組到方便的基礎介面中。
public interface UserService {
@GetMapping("/users/{id}")
User getUser(@PathVariable("id") long id);
}
@RestController
public class UserResource implements UserService {
}
@FeignClient("users")
public interface UserClient extends UserService {
}
@FeignClient 介面不應在伺服器和客戶端之間共用,並且不再支援在類別層級使用 @RequestMapping 註解 @FeignClient 介面。 |
[[feign-request/response-compression]] === Feign 請求/回應壓縮
您可以考慮為您的 Feign 請求啟用請求或回應 GZIP 壓縮。您可以透過啟用其中一個屬性來執行此操作
spring.cloud.openfeign.compression.request.enabled=true
spring.cloud.openfeign.compression.response.enabled=true
Feign 請求壓縮為您提供了類似於您可以為您的網路伺服器設定的設定
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-encoding 或 accept-encoding 標頭,則會停用該壓縮,因此當 feign.okhttp.OkHttpClient 存在於類別路徑上且 spring.cloud.openfeign.okhttp.enabled 設定為 true 時,我們不會啟用壓縮。 |
Feign 日誌記錄
為每個建立的 Feign 客戶端建立一個記錄器。預設情況下,記錄器的名稱是用於建立 Feign 客戶端的介面的完整類別名稱。Feign 日誌記錄僅回應 DEBUG
層級。
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;
}
}
Feign 功能支援
Feign 功能公開了核心 Feign 組件,以便可以修改這些組件。例如,功能可以取得 Client
、裝飾它,並將裝飾後的實例回傳給 Feign。對 Micrometer 的支援是這方面的一個很好的真實範例。請參閱 Micrometer 支援。
建立一個或多個 Capability
bean 並將它們放在 @FeignClient
組態中,可讓您註冊它們並修改所涉及的客戶端的行為。
@Configuration
public class FooConfiguration {
@Bean
Capability customCapability() {
return new CustomCapability();
}
}
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);
}
}
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
停用該功能。
Spring @RequestMapping 支援
Spring Cloud OpenFeign 提供了對 Spring @RequestMapping
註解及其衍生註解(例如 @GetMapping
、@PostMapping
和其他註解)的支援。@RequestMapping
註解上的屬性(包括 value
、method
、params
、headers
、consumes
和 produces
)由 SpringMvcContract
解析為請求的內容。
考慮以下範例
使用 params
屬性定義介面。
@FeignClient("demo")
public interface DemoTemplate {
@PostMapping(value = "/stores/{storeId}", params = "mode=upsert")
Store update(@PathVariable("storeId") Long storeId, Store store);
}
在上面的範例中,請求 url 解析為 /stores/storeId?mode=upsert
。
params 屬性也支援使用多個 key=value
或僅一個 key
-
當
params = { "key1=v1", "key2=v2" }
時,請求 url 解析為/stores/storeId?key1=v1&key2=v2
。 -
當
params = "key"
時,請求 url 解析為/stores/storeId?key
。
Feign @QueryMap 支援
Spring Cloud OpenFeign 提供了等效的 @SpringQueryMap
註解,用於將 POJO 或 Map 參數註解為查詢參數對應。
例如,Params
類別定義了參數 param1
和 param2
// 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。
HATEOAS 支援
Spring 提供了一些 API 來建立遵循 HATEOAS 原則的 REST 表示,Spring Hateoas 和 Spring Data REST。
如果您的專案使用 org.springframework.boot:spring-boot-starter-hateoas
starter 或 org.springframework.boot:spring-boot-starter-data-rest
starter,則預設情況下會啟用 Feign HATEOAS 支援。
啟用 HATEOAS 支援後,允許 Feign 客戶端序列化和反序列化 HATEOAS 表示模型:EntityModel、CollectionModel 和 PagedModel。
@FeignClient("demo")
public interface DemoTemplate {
@GetMapping(path = "/stores")
CollectionModel<Store> getStores();
}
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();
}
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);
}
反應式支援
由於 OpenFeign 專案目前不支援反應式客戶端,例如 Spring WebClient,Spring Cloud OpenFeign 也不支援。
由於 Spring Cloud OpenFeign 專案現在被認為功能完整,因此即使上游專案中提供支援,我們也不計劃新增支援。我們建議遷移到 Spring Interface Clients。那裡同時支援封鎖和反應式堆疊。
在完成之前,我們建議使用 feign-reactive 以取得 Spring WebClient 支援。
Spring Data 支援
如果 Jackson Databind 和 Spring Data Commons 在類別路徑上,則會自動新增 org.springframework.data.domain.Page
和 org.springframework.data.domain.Sort
的轉換器。
若要停用此行為,請設定
spring.cloud.openfeign.autoconfiguration.jackson.enabled=false
請參閱 org.springframework.cloud.openfeign.FeignAutoConfiguration.FeignJacksonConfiguration
以瞭解詳細資訊。
Spring @RefreshScope
支援
如果已啟用 Feign 客戶端重新整理,則每個 Feign 客戶端都會使用以下內容建立
-
feign.Request.Options
作為重新整理範圍的 bean。這表示可以針對任何 Feign 客戶端實例重新整理connectTimeout
和readTimeout
等屬性。 -
封裝在
org.springframework.cloud.openfeign.RefreshableUrl
下的 url。這表示如果使用spring.cloud.openfeign.client.config.{feignName}.url
屬性定義,則可以針對任何 Feign 客戶端實例重新整理 Feign 客戶端的 URL。
您可以透過 POST /actuator/refresh
重新整理這些屬性。
預設情況下,Feign 客戶端中的重新整理行為已停用。使用以下屬性啟用重新整理行為
spring.cloud.openfeign.client.refresh-enabled=true
請勿使用 @RefreshScope 註解註解 @FeignClient 介面。 |
OAuth2 支援
可以透過將 spring-boot-starter-oauth2-client
依賴項新增至您的專案並設定以下標誌來啟用 OAuth2 支援
spring.cloud.openfeign.oauth2.enabled=true
當標誌設定為 true,且 oauth2 客戶端內容資源詳細資訊存在時,會建立類別 OAuth2AccessTokenInterceptor
的 bean。在每個請求之前,攔截器會解析所需的存取權杖並將其作為標頭包含在內。OAuth2AccessTokenInterceptor
使用 OAuth2AuthorizedClientManager
來取得持有 OAuth2AccessToken
的 OAuth2AuthorizedClient
。如果使用者已使用 spring.cloud.openfeign.oauth2.clientRegistrationId
屬性指定 OAuth2 clientRegistrationId
,則將使用它來檢索權杖。如果未檢索到權杖或未指定 clientRegistrationId
,則將使用從 url
主機段檢索的 serviceId
。
- 提示
-
使用
serviceId
作為 OAuth2 client registrationId 對於負載平衡的 Feign 客户端來說很方便。對於非負載平衡的客户端,基於屬性的clientRegistrationId
是一個合適的方法。 - 提示
-
如果您不想使用
OAuth2AuthorizedClientManager
的預設設定,您可以直接在您的組態中實例化此類型的 bean。
轉換負載平衡的 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
來指定順序。
X-Forwarded Headers 支援
可以通過設定以下標誌來啟用 X-Forwarded-Host
和 X-Forwarded-Proto
支援
spring.cloud.loadbalancer.x-forwarded.enabled=true
為 Feign Client 提供 URL 的支援方式
您可以使用以下任何方式為 Feign client 提供 URL
案例 | 範例 | 詳細資訊 |
---|---|---|
URL 在 |
|
URL 從註解的 |
URL 在 |
|
URL 從註解的 |
URL 未在 |
|
URL 從組態屬性解析,不帶負載平衡。如果 |
URL 既未在 |
|
URL 從註解的 |
AOT 和 Native Image 支援
Spring Cloud OpenFeign 支援 Spring AOT 轉換和 Native Image,但是,僅在禁用刷新模式、禁用 Feign 客户端刷新(預設設定)和禁用 lazy `@FeignClient` 屬性解析(預設設定)的情況下。
如果您想在 AOT 或 Native Image 模式下運行 Spring Cloud OpenFeign 客户端,請確保將 spring.cloud.refresh.enabled 設定為 false 。 |
如果您想在 AOT 或 Native Image 模式下運行 Spring Cloud OpenFeign 客户端,請確保 spring.cloud.openfeign.client.refresh-enabled 未設定為 true 。 |
如果您想在 AOT 或 Native Image 模式下運行 Spring Cloud OpenFeign 客户端,請確保 spring.cloud.openfeign.lazy-attributes-resolution 未設定為 true 。 |
然而,如果您通過屬性設定 url 值,則可以通過使用 -Dspring.cloud.openfeign.client.config.[clientId].url=[url] 標誌運行映像來覆蓋 @FeignClient 的 url 值。為了啟用覆蓋,還必須通過屬性而不是在構建時通過 @FeignClient 屬性來設定 url 值。 |
組態屬性
要查看所有與 Spring Cloud OpenFeign 相關的組態屬性列表,請查看 附錄頁面。