Spring Cloud OpenFeign 功能
宣告式 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 客戶端。
如何引入 Feign
要在你的專案中引入 Feign,請使用組 ID 為 org.springframework.cloud
、artifact ID 為 spring-cloud-starter-openfeign
的啟動器。有關如何使用當前 Spring Cloud Release Train 設定構建系統的詳細資訊,請參閱 Spring Cloud 專案頁面。
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 客戶端。你也可以使用 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) 。 |
為了在多模組設定中載入 Spring Feign 客戶端 bean,你需要直接指定包。
由於 FactoryBean 物件可能在初始上下文刷新發生之前例項化,並且 Spring Cloud OpenFeign 客戶端的例項化會觸發上下文重新整理,因此不應在 FactoryBean 類中宣告它們。 |
覆蓋 Feign 預設配置
Spring Cloud 對 Feign 支援的核心概念是命名客戶端。每個 Feign 客戶端都是一組協同工作的元件的一部分,這些元件按需聯絡遠端伺服器,並且該元件集合有一個名稱,你可以使用 @FeignClient
註解作為應用開發者賦予它。Spring Cloud 使用 FeignClientsConfiguration
為每個命名客戶端按需建立一個新的元件集合作為 ApplicationContext
。這其中包含(除其他外)一個 feign.Decoder
、一個 feign.Encoder
和一個 feign.Contract
。可以使用 @FeignClient
註解的 contextId
屬性來覆蓋該元件集合的名稱。
Spring Cloud 允許你透過使用 @FeignClient
宣告附加配置(在 FeignClientsConfiguration
之上)來完全控制 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
bean名稱: 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 客戶端的使用。在使用 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,可以使用 HttpClient5FeignConfiguration.HttpClientBuilderCustomizer
介面進行程式化配置。
Apache HTTP Components 5.4 版本更改了 HttpClient 中與 HTTP/1.1 TLS 升級相關的預設設定。大多數代理伺服器可以順利處理升級,但是你可能會遇到 Envoy 或 Istio 的問題。如果需要恢復以前的行為,可以使用 HttpClient5FeignConfiguration.HttpClientBuilderCustomizer 來實現,如下面的示例所示。 |
@Configuration
public class FooConfiguration {
@Bean
public HttpClient5FeignConfiguration.HttpClientBuilderCustomizer httpClientBuilder() {
return (httpClientBuilder) -> {
RequestConfig.Builder requestConfigBuilder = RequestConfig.custom();
requestConfigBuilder.setProtocolUpgradeEnabled(false);
httpClientBuilder.setDefaultRequestConfig(requestConfigBuilder.build());
};
}
}
從 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 的預設行為不同,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");
}
}
這將用 feign.Contract.Default
替換 SpringMvcContract
,並將 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.decode-slash 的值設定為 false 來更改此行為。 |
預設情況下,Feign 客戶端不會從請求路徑中刪除尾部斜槓 / 字元。你可以透過將 spring.cloud.openfeign.client.remove-trailing-slash 的值設定為 true 來更改此行為。在下一個主要版本中,從請求路徑中刪除尾部斜槓將成為預設行為。 |
超時處理
我們可以在預設客戶端和命名客戶端上配置超時。OpenFeign 使用兩個超時引數
-
connectTimeout
防止因伺服器長時間處理而阻塞呼叫者。 -
readTimeout
從連線建立時開始應用,並在返回響應花費太長時間時觸發。
如果伺服器未執行或不可用,資料包會導致連線被拒絕。通訊要麼以錯誤訊息結束,要麼進入回退。如果 connectTimeout 設定得非常低,這可能在 connectTimeout 之前發生。執行查詢和接收此類資料包所需的時間是此延遲的重要組成部分。它會根據涉及 DNS 查詢的遠端主機而發生變化。 |
手動建立 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 原生註解。不建議將 Spring MVC 註解和 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”的普通 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
)。
使用配置屬性配置 CircuitBreakers
你可以透過配置屬性配置 CircuitBreakers。
例如,如果你有這個 Feign 客戶端
@FeignClient(url = "https://: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 = "https://:${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 = "https://:${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。為了解決這個問題,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 請求/響應壓縮
你可以考慮為你的 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
這些屬性允許你選擇性地指定壓縮的媒體型別和最小請求閾值長度。
當請求匹配 spring.cloud.openfeign.compression.request.mime-types
中設定的 MIME 型別以及 spring.cloud.openfeign.compression.request.min-request-size
中設定的大小,並且 spring.cloud.openfeign.compression.request.enabled=true
時,會將壓縮相關的頭部新增到請求中。這些頭部的功能是向伺服器發出訊號,表明客戶端期望一個壓縮的請求體。伺服器端應用的責任是根據客戶端提供的頭部資訊提供壓縮的請求體。
由於 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 Capability 支援
Feign capability 暴露了核心 Feign 元件,以便可以修改這些元件。例如,capability 可以獲取 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);
}
}
仍然可以在 Feign 中使用 MicrometerCapability
(僅度量支援),你需要停用 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
啟動器或 org.springframework.boot:spring-boot-starter-data-rest
啟動器,則預設啟用 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
註解。
如果將 Map 作為方法引數傳遞,則 @MatrixVariable
路徑段是透過將 Map 中的鍵值對用 =
連線來建立的。
如果傳遞的是不同的物件,則使用 =
將 @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);
}
Reactive 支援
在 Spring Cloud OpenFeign 積極開發期間,OpenFeign 專案 不支援響應式客戶端,例如 Spring WebClient,因此 Spring Cloud OpenFeign 也無法新增此類支援。
由於 Spring Cloud OpenFeign 專案現在被認為是功能完善的,即使上游專案提供了支援,我們也不打算新增。我們建議遷移到 Spring Interface Clients。那裡支援阻塞和響應式兩種堆疊。
Spring Data 支援
如果 Jackson Databind 和 Spring Data Commons 在 classpath 中,則會自動新增 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
作為 refresh-scoped bean。這意味著connectTimeout
和readTimeout
等屬性可以在任何 Feign 客戶端例項上重新整理。 -
包裹在
org.springframework.cloud.openfeign.RefreshableUrl
下的 URL。這意味著如果使用spring.cloud.openfeign.client.config.{feignName}.url
屬性定義了 Feign 客戶端的 URL,則可以在任何 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 客戶端註冊 ID 對於負載均衡的 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 頭支援
透過設定以下標誌可以啟用 X-Forwarded-Host
和 X-Forwarded-Proto
支援
spring.cloud.loadbalancer.x-forwarded.enabled=true
為 Feign 客戶端提供 URL 的支援方式
您可以透過以下任何一種方式為 Feign 客戶端提供 URL
情況 | 示例 | 詳情 |
---|---|---|
在 |
|
URL 從註解的 |
在 |
|
URL 從註解的 |
未在 |
|
URL 從配置屬性解析,不進行負載均衡。如果 |
既未在 |
|
URL 從註解的 |
AOT 和 Native Image 支援
Spring Cloud OpenFeign 支援 Spring AOT 轉換和 Native Image,但僅限於停用重新整理模式、停用 Feign 客戶端重新整理(預設設定)和停用 延遲 @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 相關的配置屬性列表,請檢視 附錄頁。