在Spring Cloud Netflix棧中,各個微服務都是以HTTP接口的形式暴露自身服務的,因此在調用遠程服務時就必須使用HTTP客戶端。我們可以使用JDK原生的URLConnection、Apache的Http Client、Netty的異步HTTP Client, Spring的RestTemplate。但是,用起來最方便、最優雅的還是要屬Feign了。
Feign簡介
Feign是一種聲明式、模板化的HTTP客戶端。在Spring Cloud中使用Feign, 我們可以做到使用HTTP請求遠程服務時能與調用本地方法一樣的編碼體驗,開發者完全感知不到這是遠程方法,更感知不到這是個HTTP請求。比如:
@Autowiredprivate AdvertGropRemoteService service; // 遠程服務public AdvertGroupVO foo(Integer groupId) { return service.findByGroupId(groupId); // 通過HTTP調用遠程服務}
開發者通過service.findByGroupId()
就能完成發送HTTP請求和解碼HTTP返回結果并封裝成對象的過程。
Feign的定義
為了讓Feign知道在調用方法時應該向哪個地址發請求以及請求需要帶哪些參數,我們需要定義一個接口:
@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注入。
B: @RequestMapping表示在調用該方法時需要向/group/{groupId}
發送GET請求。
C: @PathVariable與SpringMVC中對應注解含義相同。
Spring Cloud應用在啟動時,Feign會掃描標有@FeignClient注解的接口,生成代理,并注冊到Spring容器中。生成代理時Feign會為每個接口方法創建一個RequetTemplate對象,該對象封裝了HTTP請求需要的全部信息,請求參數名、請求方法等信息都是在這個過程中確定的,Feign的模板化就體現在這里。
在本例中,我們將Feign與Eureka和Ribbon組合使用,@FeignClient(name = "ea")
意為通知Feign在調用該接口方法時要向Eureka中查詢名為ea的服務,從而得到服務URL。
Feign的Encoder、Decoder和ErrorDecoder
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接口拋出業務異常以供調用者處理。
新聞熱點
疑難解答