Feign是一個Web服務的客戶端框架。它讓Web服務的客戶端開發變得更容易。 只須要使用Feign建立一個接口加上一個註解就好了。Feign和JAX-RS提供一整套插件化的註解配置方式。在Feign中還可使用插件化的編碼器和解碼器。java
Spring Cloud 還提供一個
HttpMessageConverters
,這樣當使用Spring Web環境時,就能夠支持Spring MVC。 在使用Feign時,Spring Cloud還能夠整合Ribbon和Eureka,爲http客戶端提供負載均衡的能力。git
在工程中引入Feign只須要引入依賴就行:group :
org.springframework.cloud
artifact id :spring-cloud-starter-feign
。詳情見Spring Cloud相關文檔github
例如:web
@Configuration @ComponentScan @EnableAutoConfiguration @EnableEurekaClient @EnableFeignClients public class Application { public static void main(String[] args) { SpringApplication.run(Application.class, args); } }
StoreClient.javaspring
@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); }
在
@FeignClient
中使用一個字符串(例子中的"stores")來指定客戶端名字,這個名字也將被用於一個Ribbon負載均衡器。 還能夠配置url
屬性來指定URL。 在Spring容器中會使用全限定名做爲這個Bean的名稱。一樣,能夠經過name
屬性進行自定義。 在上例中,經過@Qualifier("storesFeignClient")
就能夠引用到這個Bean。 若是須要改變默認引用名稱,能夠在@FeignClient
中配置qualifier
屬性。apache
Ribbon客戶端將會查找"stores"服務的物理地址。 若是是一個Eureka客戶端應用,那麼將會自動註冊到Eureka中。 若是不想使用Eureka,能夠簡單的配置一個服務列表,手動指定服務。json
Spring Cloud 的 Feign有一個核心概念,那就是客戶端命名。每個Feign客戶端都是集羣中一組
@FeignClient
標記的可用服務區域中的一部分。app
Spring Cloud會爲每個命名的Feign客戶端中的
FeignClientsConfiguration
建立一個新的ApplicationContext
。 這其中會包括一個feign.Decoder
,一個feign.Encoder
,以及一個feign.Contract
。負載均衡
Spring Cloud運行開發者經過
@FeignClient
對Feign客戶端進行徹底的控制。例如:框架
@FeignClient(name = "stores", configuration = FooConfiguration.class) public interface StoreClient { //.. }
在這個例子中,客戶端使用一個自定義的
FooConfiguration
整合到FeignClientsConfiguration
的配置過程。
警告:
須要確保
FooConfiguration
不會被@Configuration
或者@ComponentScan
掃描到,不然,就會被全部@FeignClient
共享了(自動注入)。若是使用@ComponentScan
或者@SpringBootApplication
時,也須要避免FooConfiguration
被自動掃描。
注意:
serviceId
屬性已經丟棄,不建議使用,改用name
屬性進行配置。
警告:
之前使用
url
屬性時,不須要name
。如今不行了,name
必須指定。
在
name
和url
屬性時,可使用佔位符進行配置。例如:
@FeignClient(name = "${feign.name}", url = "${feign.url}") public interface StoreClient { //.. }
Spring Cloud Netflix 默認會建立下列Bean
類型 | Bean名稱 | 類名 | 備註 |
---|---|---|---|
Decoder |
feignDecoder | ResponseEntityDecoder |
包裝了SpringDecoder |
Encoder |
feignEncoder | SpringEncoder |
|
Logger |
feignLogger | Slf4jLogger |
|
Contract |
feignContract | SpringMvcContract |
|
Feign.Builder |
feignBuilder | HystrixFeign.Builder |
|
Client |
feignClient | LoadBalancerFeignClient |
若是啓用Ribbon則是LoadBalancerFeignClient ,不然使用Feign默認客戶端 |
還能夠經過
feign.okhttp.enabled
或者feign.httpclient.enabled
來開啓OkHttpClient和ApacheHttpClient,固然前提是classpath中必須有這些相關依賴。
默認狀況下,Spring Cloud Netflix不會爲Feign提供下列的Bean,可是仍然能夠在spring上下文中經過類型找到它們來建立Feign客戶端。
Logger.Level
Retryer
ErrorDecoder
Request.Options
Collection<RequestInterceptor>
能夠在
@FeignClient
的配置類中,自行建立這些Bean來訂製Feign客戶端。例如:
@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
。
默認配置能夠經過
@EnableFeignClients
的defaultConfiguration
屬性來制定。這些配置,會被應用到全部的Feign客戶端上。
在某些場景中,經過上述方法,仍是不能獲得一個想要的Feign客戶端。 那這個時候,就須要本身經過Feign Builder API來手動建立客戶端。 下面這個例子就展示了爲同一個接口建立兩個不一樣配置的客戶端。
@Import(FeignClientsConfiguration.class) class FooController { private FooClient fooClient; private FooClient adminClient; @Autowired public FooController( ResponseEntityDecoder decoder, SpringEncoder encoder, Client client) { this.fooClient = Feign.builder().client(client) .encoder(encoder) .decoder(decoder) .requestInterceptor(new BasicAuthRequestInterceptor("user", "user")) .target(FooClient.class, "http://PROD-SVC"); this.adminClient = Feign.builder().client(client) .encoder(encoder) .decoder(decoder) .requestInterceptor(new BasicAuthRequestInterceptor("admin", "admin")) .target(FooClient.class, "http://PROD-SVC"); } }
注意: 上例中FeignClientsConfiguration.class
是Spring Cloud Netflix提供的默認配置類。
注意: PROD-SVC
是服務的客戶端請求時標記的名稱。
若是在classpath中加入了Hystrix,那默認Feign就會爲全部方法都包裝上一個斷路器。也會返回一個
com.netflix.hystrix.HystrixCommand
。這就會致使可使用正則匹配(如:調用.toObservable()
or.observe()
)或者異步請求(如:調用.queue()
)。
若是不想在Feign使用Hystrix,能夠配置:
feign.hystrix.enabled=false
。
若是想讓每一個客戶端都不使用Hystrix,能夠在
prototype
做用域中建立一個普通的Feign.Builder
實現。例如:
@Configuration public class FooConfiguration { @Bean @Scope("prototype") public Feign.Builder feignBuilder() { return Feign.builder(); } }
Hystrix中的降級概念:當鏈路中發生錯誤是,執行一個默認的代碼邏輯。 能夠在
@FeignClient
中配置fallback
屬性,來開啓Feign降級處理。例如:
@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"); } }
若是想在降級操做中處理拋出的異常,可使用
@FeignClient
的fallbackFactory
屬性。例如:
@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 HystrixClientWithFallBackFactory() { @Override public Hello iFailSometimes() { return new Hello("fallback; reason was: " + cause.getMessage()); } }; } }
警告: Feign的降級操做與Hystrix降級操做對比有一個限制。降級操做,對於方法的返回類型目前還不支持com.netflix.hystrix.HystrixCommand
和rx.Observable
。
Feign只支持接口層的單繼承。能夠將一些通用操做抽象成一個基礎接口。例如:
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 { }
注意: 服務端和客戶端共用一個接口,一般來講並不建議這樣作。這樣耦合過大,並且在當前Spring MVC版本中也不支持這種方式(共用接口)。
能夠考慮對Feign的request和response開啓GZIP壓縮處理。能夠在配置文件中經過以下配置開啓:
feign.compression.request.enabled=true feign.compression.response.enabled=true
在web服務中進行更詳細的配置:
feign.compression.request.enabled=true feign.compression.request.mime-types=text/xml,application/xml,application/json feign.compression.request.min-request-size=2048
上例中,指定了Media type和壓縮的最小大小進行了指定。
對於建立的每一個Feign客戶端都會建立一個Logger。默認狀況下,使用客戶端全類名做爲日誌名,Feign日誌只能設置爲
DEBUG
級別。
application.yml
logging.level.project.user.UserClient: DEBUG
能夠爲每一個客戶端配置一個
Logger.Level
對象,來告訴Feign如何輸出日誌。能夠選擇如下級別:
NONE
,無日誌(默認)BASIC
,僅輸出請求的方法、URL、response status code 以及執行時間HEADERS
,帶上request和response的header信息FULL
,包括requset和response的header,body以及元數據例如:
@Configuration public class FooConfiguration { @Bean Logger.Level feignLoggerLevel() { return Logger.Level.FULL; } }
Archaius是一個Netflix客戶端配置的類庫。這個類庫能夠被用於全部的Netflix OSS組件的配置。Archaius是在Apache Commons Configuration的基礎山進行擴展出來的。Archaius容許客戶端輪詢自動發現配置的改動變化。Archaius經過
Dynamic<Type>Property
類來處理各類配置屬性。
Archaius Example
class ArchaiusTest { DynamicStringProperty myprop = DynamicPropertyFactory .getInstance() .getStringProperty("my.prop"); void doSomething() { OtherClass.someMethod(myprop.get()); } }
Archaius有本身的配置文件集以及預先加載機制。Spring應用一般不會直接使用Archaius,而是經過Netflix原生的配置工具進行使用。Spring Cloud提供一個Spring Environment來對Archaius屬性進行橋接使用。這樣就可讓Spring Boot應用能像使用普通配置屬性同樣使用Archaius。