在Spring Cloud Netflix棧中,各個微服務都是以HTTP接口的形式暴露自身服務的,所以在調用遠程服務時就必須使用HTTP客戶端。咱們可使用JDK原生的URLConnection
、Apache的Http Client
、Netty的異步HTTP Client, Spring的RestTemplate
。可是,用起來最方便、最優雅的仍是要屬Feign了。css
Feign是一種聲明式、模板化的HTTP客戶端。在Spring Cloud中使用Feign, 咱們能夠作到使用HTTP請求遠程服務時能與調用本地方法同樣的編碼體驗,開發者徹底感知不到這是遠程方法,更感知不到這是個HTTP請求。好比:java
@Autowired private AdvertGropRemoteService service; // 遠程服務 public AdvertGroupVO foo(Integer groupId) { return service.findByGroupId(groupId); // 經過HTTP調用遠程服務 }
開發者經過service.findByGroupId()
就能完成發送HTTP請求和解碼HTTP返回結果並封裝成對象的過程。apache
爲了讓Feign知道在調用方法時應該向哪一個地址發請求以及請求須要帶哪些參數,咱們須要定義一個接口:json
@FeignClient(name = "ea") // [A] public interface AdvertGroupRemoteService { @RequestMapping(value = "/group/{groupId}", method = RequestMethod.GET) // [B] AdvertGroupVO findByGroupId(@PathVariable("groupId") Integer adGroupId) // [C] @RequestMapping(value = "/group/{groupId}", method = RequestMethod.PUT) void update(@PathVariable("groupId") Integer groupId, @RequestParam("groupName") String groupName)
A: @FeignClient
用於通知Feign組件對該接口進行代理(不須要編寫接口實現),使用者可直接經過@Autowired
注入。markdown
B: @RequestMapping
表示在調用該方法時須要向/group/{groupId}
發送GET
請求。app
C: @PathVariable
與SpringMVC
中對應註解含義相同。異步
Spring Cloud應用在啓動時,Feign會掃描標有@FeignClient
註解的接口,生成代理,並註冊到Spring容器中。生成代理時Feign會爲每一個接口方法建立一個RequetTemplate
對象,該對象封裝了HTTP請求須要的所有信息,請求參數名、請求方法等信息都是在這個過程當中肯定的,Feign的模板化就體如今這裏。微服務
在本例中,咱們將Feign與Eureka和Ribbon組合使用,@FeignClient(name = "ea")
意爲通知Feign在調用該接口方法時要向Eureka中查詢名爲ea
的服務,從而獲得服務URL。性能
Feign將方法簽名中方法參數對象序列化爲請求參數放到HTTP請求中的過程,是由編碼器(Encoder)完成的。同理,將HTTP響應數據反序列化爲java對象是由解碼器(Decoder)完成的。編碼
默認狀況下,Feign會將標有@RequestParam
註解的參數轉換成字符串添加到URL中,將沒有註解的參數經過Jackson轉換成json放到請求體中。注意,若是在@RequetMapping
中的method
將請求方式指定爲POST
,那麼全部未標註解的參數將會被忽略,例如:
@RequestMapping(value = "/group/{groupId}", method = RequestMethod.GET) void update(@PathVariable("groupId") Integer groupId, @RequestParam("groupName") String groupName, DataObject obj);
此時由於聲明的是GET請求沒有請求體,因此obj
參數就會被忽略。
在Spring Cloud環境下,Feign的Encoder*只會用來編碼沒有添加註解的參數*。若是你自定義了Encoder, 那麼只有在編碼obj
參數時纔會調用你的Encoder。對於Decoder, 默認會委託給SpringMVC中的MappingJackson2HttpMessageConverter
類進行解碼。只有當狀態碼不在200 ~ 300之間時ErrorDecoder纔會被調用。ErrorDecoder的做用是能夠根據HTTP響應信息返回一個異常,該異常能夠在調用Feign接口的地方被捕獲到。咱們目前就經過ErrorDecoder來使Feign接口拋出業務異常以供調用者處理。
Feign在默認狀況下使用的是JDK原生的URLConnection
發送HTTP請求,沒有鏈接池,可是對每一個地址會保持一個長鏈接,即利用HTTP的persistence connection
。咱們能夠用Apache的HTTP Client替換Feign原始的http client, 從而獲取鏈接池、超時時間等與性能息息相關的控制能力。Spring Cloud從Brixtion.SR5
版本開始支持這種替換,首先在項目中聲明Apache HTTP Client和feign-httpclient
依賴:
<!-- 使用Apache HttpClient替換Feign原生httpclient --> <dependency> <groupId>org.apache.httpcomponents</groupId> <artifactId>httpclient</artifactId> </dependency> <dependency> <groupId>com.netflix.feign</groupId> <artifactId>feign-httpclient</artifactId> <version>${feign-httpclient}</version> </dependency>
而後在application.properties
中添加:
feign.httpclient.enabled=true
經過Feign, 咱們能把HTTP遠程調用對開發者徹底透明,獲得與調用本地方法一致的編碼體驗。這一點與阿里Dubbo中暴露遠程服務的方式相似,區別在於Dubbo是基於私有二進制協議,而Feign本質上仍是個HTTP客戶端。若是是在用Spring Cloud Netflix搭建微服務,那麼Feign無疑是最佳選擇。