Spring Cloud OpenFeign
1. 聲明性 REST 客戶端:Feign
Feign是聲明性Web服務客戶端。 它使編寫Web服務客戶端更加容易。 要使用Feign,請創建一個接口並對其進行注釋。 它具有可插入注釋支持,包括Feign注釋和JAX-RS注釋。 Feign還支持可插拔編碼器和解碼器。 Spring Cloud添加了對Spring MVC注釋的支持,並支持使用Spring Web中默認使用的注釋。 Spring Cloud集成了Ribbon和Eureka以及Spring Cloud LoadBalancer以在使用Feign.HttpMessageConverters時提供負載平衡的HTTP客戶端
1.1. 如何包括費因
要將Feign包含在您的項目中,請使用具有組和工件ID的啟動器。
Example 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(); @RequestMapping(method = RequestMethod.POST, value = "/stores/{storeId}", consumes = "application/json") Store update(@PathVariable("storeId") Long storeId, Store store); }
在注釋中,字符串值(上面的“ stores”)是一個任意的客戶端名稱,用於創建Ribbon負載平衡器(請參閱下面的功能區支持詳細信息)或Spring Cloud LoadBalancer。 您還可以使用屬性(絕對值或僅主機名)指定URL。 應用程序上下文中的Bean名稱是接口的標准名稱。 要指定自己的別名值,可以使用批注的值。@ FeignClienturlqualifier @ FeignClient
上面的負載平衡器客戶端將希望發現“商店”服務的物理地址。 如果您的應用程序是Eureka客戶端,則它將在Eureka服務注冊表中解析該服務。 如果您不想使用Eureka,只需使用SimpleDiscoveryClient在外部配置中配置服務器列表即可。
為了保持向后兼容性,被用作默認的負載均衡器實現。 但是,Spring Cloud Netflix Ribbon現在處於維護模式,因此我們建議改用Spring Cloud LoadBalancer。spring.cloud.loadbalancer.ribbon.enabled false |
1.2. Overriding Feign Defaults
Spring Cloud的Feign支持的中心概念是指定客戶的概念。 每個偽客戶端都是組件集合的一部分,這些組件可以一起工作以按需聯系遠程服務器,並且該集合的名稱是您使用注釋將其指定為應用程序開發人員的。 Spring Cloud使用來為每個命名客戶端按需創建一個新集合。 這包含(除其他事項外)an,a和a。 通過使用批注的屬性,可以覆蓋該集合的名稱。@ FeignClientApplicationContextFeignClientsConfigurationfeign.Decoderfeign.Encoderfeign.ContractcontextId @ FeignClient
Spring Cloud通過使用聲明其他配置(位於之上),使您可以完全控制假客戶端。
示例:FeignClientsConfiguration @ FeignClient
@FeignClient(name = "stores", configuration = FooConfiguration.class) public interface StoreClient { }
在這種情況下,客戶端由已經存在的組件以及任何in組成(后者將覆蓋前者).FeignClientsConfigurationFooConfiguration
FooConfiguration不需要使用注釋。 但是,如果是這樣,請注意將其從任何其他不包括此配置的配置中排除,因為當指定時它將成為,,等的默認來源。 可以通過將其與or或放在單獨的,不重疊的包中來避免這種情況,也可以在中明確排除它。 @ Configuration @ ComponentScanfeign.Decoderfeign.Encoderfeign.Contract @ ComponentScan @ SpringBootApplication @ ComponentScan |
現在不推薦使用該屬性,而推薦使用該屬性。 serviceIdname |
除了更改集合的名稱之外,還使用注釋的屬性,它將覆蓋客戶機名稱的別名,並將其用作為該客戶機創建的配置Bean名稱的一部分。 contextId @ FeignClientApplicationContext
|
and 屬性中支持占位符。name
url
@FeignClient(name = "${feign.name}", url = "${feign.url}") public interface StoreClient { }
Spring Cloud Netflix默認為偽裝提供以下bean(beanName:):BeanType
ClassName
-
Decoder
feignDecoder: (which wraps aResponseEntityDecoder
SpringDecoder
) -
Encoder
feignEncoder:SpringEncoder
-
Logger
feignLogger:Slf4jLogger
-
Contract
feignContract:SpringMvcContract
-
Feign.Builder
feignBuilder:HystrixFeign.Builder
-
Client
feignClient:如果Ribbon在類路徑中且已啟用,則為a;否則,如果Spring Cloud LoadBalancer在類路徑中,則使用。 如果它們都不在類路徑中,則使用默認的偽裝客戶端。LoadBalancerFeignClient
FeignBlockingLoadBalancerClient
spring-cloud-starter-openfeign 同時包含 pring-cloud-starter-netflix-ribbon spring-cloud-starter-loadbalancer |
OkHttpClient和ApacheHttpClient偽裝客戶端可以通過分別將或設置為,並將它們放在類路徑中來使用。 您可以通過在使用Apache或使用OK HTTP時提供一個bean來定制HTTP客戶端。feign.okhttp.enabled
feign.httpclient.enabled
true
org.apache.http.impl.client.CloseableHttpClient
okhttp3.OkHttpClient
默認情況下,Spring Cloud Netflix不會為偽裝提供以下bean,但仍會從應用程序上下文中查找這些類型的bean以創建偽裝客戶端:
-
Logger.Level
-
Retryer
-
ErrorDecoder
-
Request.Options
-
Collection<RequestInterceptor>
-
SetterFactory
-
QueryMapEncoder
創建這些類型之一的bean並將其放置在配置中(例如上述配置),您可以覆蓋所描述的每個bean。
Example: @FeignClient
FooConfiguration
@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
feign:
client:
config:
feignName:
connectTimeout: 5000
readTimeout: 5000
loggerLevel: full
errorDecoder: com.example.SimpleErrorDecoder
retryer: com.example.SimpleRetryer
requestInterceptors:
- com.example.FooRequestInterceptor
- com.example.BarRequestInterceptor
decode404: false
encoder: com.example.SimpleEncoder
decoder: com.example.SimpleDecoder
contract: com.example.SimpleContract
可以按照與上述類似的方式在屬性中指定默認配置。 區別在於此配置將應用於所有虛擬客戶端。@ EnableFeignClients defaultConfiguration
application程序.yml
feign:
client:
config:
default:
connectTimeout: 5000
readTimeout: 5000
loggerLevel: basic
如果我們同時創建bean和配置屬性,則配置屬性將獲勝。 它將覆蓋值。
但是,如果要將優先級更改為,則可以更改為
@Configuration
@Configuration
@Configuration
feign.client.default-to-properties
false
如果您需要使用綁定變量或在Feign中禁用Hystrix。 ThreadLocal RequestInterceptor`s you will need to either set the thread isolation strategy for Hystrix to `SEMAPHORE |
應用程序.yml
# To disable Hystrix in Feign
feign:
hystrix:
enabled: false
# To set thread isolation to SEMAPHORE
hystrix:
command:
default:
execution:
isolation:
strategy: SEMAPHORE
如果我們要創建多個具有相同名稱或URL的偽客戶端,以便它們指向同一台服務器,但每個客戶端具有不同的自定義配置,則必須使用的屬性,以避免這些配置Bean發生名稱沖突。 contextId
@FeignClient
@FeignClient(contextId = "fooClient", name = "stores", configuration = FooConfiguration.class) public interface FooClient { }
@FeignClient(contextId = "barClient", name = "stores", configuration = BarConfiguration.class) public interface BarClient { }
1.3. 手動創建 Feign Clients
在某些情況下,可能有必要使用上述方法無法實現的方式自定義Feign客戶。 在這種情況下,您可以使用Feign Builder API創建客戶端。 下面是一個示例,該示例創建具有相同接口的兩個Feign Client,但為每個Feign Client配置一個單獨的請求攔截器。
@Import(FeignClientsConfiguration.class) class FooController { private FooClient fooClient; private FooClient adminClient; @Autowired public FooController(Decoder decoder, Encoder encoder, Client client, Contract contract) { this.fooClient = Feign.builder().client(client) .encoder(encoder) .decoder(decoder) .contract(contract) .requestInterceptor(new BasicAuthRequestInterceptor("user", "user")) .target(FooClient.class, "https://PROD-SVC"); this.adminClient = Feign.builder().client(client) .encoder(encoder) .decoder(decoder) .contract(contract) .requestInterceptor(new BasicAuthRequestInterceptor("admin", "admin")) .target(FooClient.class, "https://PROD-SVC"); } }
在上面的示例中是春雲 Netflix 提供的默認配置。FeignClientsConfiguration.class |
PROD-SVC是客戶端將向其請求的服務的名稱。 |
Feign對象定義在接口上有效的注釋和值。 自動裝配的bean提供對SpringMVC注釋的支持,而不是默認的Feign本機注釋。Contract Contract |
1.4. Feign Hystrix 支持
如果Hystrix在classpath和上,Feign將使用斷路器包裝所有方法。 還可以返回a。 這樣一來,您就可以使用反應性模式(調用或或異步使用(調用)
feign.hystrix.enabled=true
com.netflix.hystrix.HystrixCommand
.toObservable()
.observe()
.queue()
要基於每個客戶端禁用Hystrix支持,請使用 "prototype"作用域
例如:Feign.Builder
@Configuration public class FooConfiguration { @Bean @Scope("prototype") public Feign.Builder feignBuilder() { return Feign.builder(); } }
在Spring Cloud Dalston發行之前,如果Hystrix在類路徑中,Feign默認會將所有方法包裝在斷路器中。 Spring Cloud Dalston中更改了此默認行為,以支持選擇加入方法 |
1.5. Feign Hystrix Fallbacks
Hystrix支持回退的概念:當它們的電路斷開或出現錯誤時執行的默認代碼路徑。
要為給定集啟用后備,該屬性應為實現后備的類名稱。
您還需要將實現聲明為Spring bean。
@FeignClient
fallback
@FeignClient(name = "hello", fallback = HystrixClientFallback.class) protected interface HystrixClient { @RequestMapping(method = RequestMethod.GET, value = "/hello") Hello iFailSometimes(); } static class HystrixClientFallback implements HystrixClient { @Override public Hello iFailSometimes() { return new Hello("fallback"); } }
如果需要訪問引起回退觸發器的原因,則可以使用內部的屬性。fallbackFactory
@FeignClient
@FeignClient(name = "hello", fallbackFactory = HystrixClientFallbackFactory.class) protected interface HystrixClient { @RequestMapping(method = RequestMethod.GET, value = "/hello") Hello iFailSometimes(); } @Component static class HystrixClientFallbackFactory implements FallbackFactory<HystrixClient> { @Override public HystrixClient create(Throwable cause) { return new HystrixClient() { @Override public Hello iFailSometimes() { return new Hello("fallback; reason was: " + cause.getMessage()); } }; } }
1.6.Feign and @Primary
將Feign與Hystrix后備一起使用時,同一類型的多個bean。 這將導致無法正常運行,因為實際上並沒有一個bean,也沒有一個標記為主要的bean。 為了解決這個問題,Spring Cloud Netflix將所有Feign實例標記為,因此Spring Framework將知道要注入哪個bean。 在某些情況下,這可能不是理想的。 要關閉此行為,請將屬性設置為false。ApplicationContext
@Autowired
@Primary
primary
@FeignClient
@FeignClient(name = "hello", primary = false) public interface HelloClient { }
1.7. Feign 繼承 支持
Feign通過單繼承接口支持樣板API。 這允許將常用操作分組為方便的基本接口。
UserService.java
public interface UserService { @RequestMapping(method = RequestMethod.GET, value ="/users/{id}") User getUser(@PathVariable("id") long id); }
@RestController public class UserResource implements UserService { }
package project.user; @FeignClient("users") public interface UserClient extends UserService { }
通常不建議在服務器和客戶端之間共享接口。 它引入了緊密耦合,並且實際上也無法以當前形式與Spring MVC一起使用(方法參數映射不被繼承)。1.8. 費恩請求/響應壓縮 |
1.8. Feign request/response 壓縮
您可以考慮為您的Feign請求啟用請求或響應GZIP壓縮。 您可以通過啟用以下屬性之一來做到這一點:
feign.compression.request.enabled=true feign.compression.response.enabled=true
Feign 請求壓縮為您提供了類似於為 Web 服務器設置的設置:
feign.compression.request.enabled=true feign.compression.request.mime-types=text/xml,application/xml,application/json feign.compression.request.min-request-size=2048
這些屬性允許您對壓縮介質類型和最小請求閾值長度進行選擇性選擇。
對於除 OkHttpClient 外的 http 客戶端,可以啟用默認 gzip 解碼器以 UTF-8 編碼解碼 gzip 響應:
feign.compression.response.enabled=true feign.compression.response.useGzipDecoder=true
1.9. Feign Logging
為每個創建的 Feign 客戶端創建一個記錄器。默認情況下,記錄器的名稱是用於創建 Feign 客戶端的接口的完整類名稱。Feign 日志記錄僅響應級別。DEBUG
logging.level.project.user.UserClient: DEBUG
每個客戶端可以配置的對象告訴 Feign 要記錄多少。選項包括:Logger.Level
-
NONE
,無日志記錄(DEFAULT)。 -
BASIC
,只記錄請求方法和 URL 以及響應狀態代碼和執行時間。 -
HEADERS
,將基本信息連同請求和響應標頭一起記錄。 -
FULL
,記錄請求和響應的標頭、正文和元數據。
例如,以下將 設置為 :Logger.Level
FULL
@Configuration public class FooConfiguration { @Bean Logger.Level feignLoggerLevel() { return Logger.Level.FULL; } }
1.10.Feign @QueryMap support
OpenFeign批注支持將POJO用作GET參數映射。 不幸的是,默認的OpenFeign QueryMap注釋與Spring不兼容,因為它缺少屬性。@QueryMap
value
Spring Cloud OpenFeign提供了等效的注釋,用於將POJO或Map參數注釋為查詢參數map。@ SpringQueryMap
例如,定義參數 :Params
param1
param2
// Params.java public class Params { private String param1; private String param2; // [Getters and setters omitted for brevity] }
以下Feign客戶端使用注釋使用 類:Params
@SpringQueryMap
@FeignClient("demo") public interface DemoTemplate { @GetMapping(path = "/demo") String demoEndpoint(@SpringQueryMap Params params); }
如果需要對生成的查詢參數映射進行更多控制,則可以實現一個自定義bean.QueryMapEncoder
1.11. HATEOAS 支持
Spring 提供了一些 API,以創建遵循HATEOAS原則的 REST 表示形式。
如果項目使用啟動器或啟動器,則默認啟用 Feign HATEOAS 支持。org.springframework.boot:spring-boot-starter-hateoas
org.springframework.boot:spring-boot-starter-data-rest
啟用 HATEOAS 支持后,允許 Feign 客戶端序列化並反序列化 HATEOAS 表示模型:實體模型、集合模型和pagedModel。
@FeignClient("demo") public interface DemoTemplate { @GetMapping(path = "/stores") CollectionModel<Store> getStores(); }
1.12. Spring @MatrixVariable 支持
春雲 OpenFeign 為春季注釋提供支持。@MatrixVariable
如果映射作為方法參數傳遞,則路徑段是通過將鍵值對從映射與 聯接 來創建。@MatrixVariable
=
如果傳遞了其他對象,則注釋中提供(如果已定義)或注釋化變量名稱將使用 提供的方法參數與 聯接。name
@MatrixVariable
=
- 重要
-
即使在服務器端,Spring 並不要求用戶命名路徑段占位符與矩陣變量名稱相同,因為它在客戶端上過於模糊,Sprig Cloud OpenFeign 要求您添加具有與注釋中提供的名稱(如果已定義)或注釋化變量名稱匹配的路徑段占位符。
name
@MatrixVariable
例如:
@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.13. 故障排除
1.13.1. 早期初始化錯誤
根據使用 Feign 客戶端的方式,在啟動應用程序時可能會看到初始化錯誤。要解決此問題,您可以在自動連接客戶端時使用 。ObjectProvider
@Autowired ObjectProvider<TestFeginClient> testFeginClient;