Feign是一種聲明式、模板化的REST客戶端。在Spring Cloud中使用Feign, 我們可以做到使用HTTP請求遠程服務時能與調用本地方法一樣的編碼體驗,開發者完全感知不到這是遠程方法,省略了大量的http請求代碼。
開始使用Feign
Spring Cloud提供了完備的Feign配置啓動功能。
- 在pom.xml中引入Feign依賴,添加如下內容:
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-openfeign</artifactId>
</dependency>
<!-- 使用httpclient作爲遠程調用的實現,如果不引入默認使用jdk的HttpURLConnection -->
<dependency>
<groupId>io.github.openfeign</groupId>
<artifactId>feign-httpclient</artifactId>
</dependency>
- 在有@Configuration註解的類中增加@EnableFeignClients註解開啓功能,比如在springboot啓動類中:
@Configuration
@EnableFeignClients
public class MyApplication {}
- 聲明接口
@FeignClient(name = "query", url = "http://www.baidu.com")
public interface BaiduClient {
@RequestMapping(value = "/")
Map<String,Object> query(@RequestParam("wd") String wd);
}
- 直接在其他bean中注入接口並調用
@RestController
public class TestController {
@Autowired
private BaiduClient client;
@GetMapping("/query")
public Object name(@RequestParam("wd") String wd) {
return client.query(wd);
}
}
開發配置
Feign通過@FeignClient註解聲明一個service,@FeignClient必須聲明在inteface上。Feign通過在接口方法上使用註解聲明具體的請求url地址、綁定參數。openFeign直接使用了Spring MVC中的地址映射和參數綁定註解,如@RequestMapping,@PathVariable,@RequestParam等。需要注意的是,在定義各參數綁定時@RequestParam、@RequestHeader等可以指定參數名稱的註解,他們的value也不能少,在Spring MVC程序中,這些註解會根據參數名稱來作爲默認值,但是Feign中綁定參數必須通過value屬性指明具體的參數名,不然拋出口 lllegalStateException 異常, value 屬性不能爲空。
FeignClient語法
@FeignClient註解的常用屬性如下:
- name:指定FeignClient的名稱,如果項目使用了Ribbon,name屬性會作爲微服務的名稱,用於服務發現
- url: 手動指定@FeignClient調用的地址
- decode404:當發生http 404錯誤時,如果該字段位true,會調用decoder進行解碼,否則拋出 FeignException
- configuration: Feign配置類,可以自定義Feign的Encoder、Decoder、LogLevel、Contract
- fallback: 定義容錯的處理類,當調用遠程接口失敗或超時時,會調用對應接口的容錯邏輯,fallback指定的類必須實現@FeignClient標記的接口
- fallbackFactory: 工廠類,用於生成fallback類示例,通過這個屬性我們可以實現每個接口通用的容錯邏輯,減少重複的代碼
- path: 定義當前FeignClient的統一前綴
Feign請求超時問題
Hystrix默認的超時時間是1秒,如果超過這個時間尚未響應,將會進入fallback代碼。而首次請求往往會比較慢(因爲Spring的懶加載機制,要實例化一些類),這個響應時間可能就大於1秒了
解決方案有三種,以feign爲例。
方法一
hystrix.command.default.execution.isolation.thread.timeoutInMilliseconds: 5000
該配置是讓Hystrix的超時時間改爲5秒
方法二 hystrix.command.default.execution.timeout.enabled: false
該配置,用於禁用Hystrix的超時時間
方法三 feign.hystrix.enabled: false
該配置,用於索性禁用feign的hystrix。該做法除非一些特殊場景,不推薦使用。
這篇文章對Feign的超時配置做了詳細分析,值得學習。
“Spring Cloud中Feign的使用方法以及原理解析”http://www.itersblog.com/archives/24.html
參數綁定
GET請求
對應form表單形式的get請求"GET /get?id=xx&username=yyy",可以按如下方式聲明:
@RequestMapping(value = "/get", method = RequestMethod.GET)
public User get1(@RequestParam("id") Long id, @RequestParam("username") String username);
如果參數比較多,可以通過Map批量聲明參數:
@RequestMapping(value = "/get", method = RequestMethod.GET)
public User get2(@RequestParam Map<String, Object> map);
POST請求
通常的post請求都是以json格式提交數據的,Feign支持將對象直接轉換爲json的請求方式:
@RequestMapping(value = "/post", method = RequestMethod.POST)
public User post(@RequestBody User user);
有些歷史遺留系統post請求是按from表單的格式提交的,這時需要特殊處理:
@FeignClient(name = "xxx", url = "http://www.itmuch.com/", configuration = TestFeignClient.FormSupportConfig.class)
public interface TestFeignClient {
@PostMapping(value = "/test",
consumes = {MediaType.APPLICATION_FORM_URLENCODED_VALUE},
produces = {MediaType.APPLICATION_JSON_UTF8_VALUE}
)
void post(Map<String, ?> queryParam);
class FormSupportConfig {
@Autowired
private ObjectFactory<HttpMessageConverters> messageConverters;
// new一個form編碼器,實現支持form表單提交
@Bean
public Encoder feignFormEncoder() {
return new SpringFormEncoder(new SpringEncoder(messageConverters));
}
}
}
說明:這裏FormSupportConfig內部有@Bean聲明,可以不加@Configuration註解。
自定義配置
@FeignClient的configuration()提供了我們自定義請求配置的能力。在實際工作中我們會遇到很多個性化的需求都可以通過這個屬性注入。比如加密驗籤、特殊映射方案處理、超時配置等。
接口安全認證
調用需要安全認證的系統時,我們需要添加認證信息,這時可以通過RequestInterceptor對請求實現攔截和自動注入。feign提供了http basic安全認證攔截器 BasicAuthRequestInterceptor。
@FeignClient(value = "auth-server", configuration = AuthServerClient.AuthServerFeignClientConfiguration.class)
public interface AuthServerClient {
@GetMapping("/oauth/token_key")
Map getTokenKey();
@Configuration
class AuthServerFeignClientConfiguration {
@Value("${authServer.security.clientId}")
private String clientId;
@Value("${authServer.security.clientSecret}")
private String clientSecret;
@Bean
public BasicAuthRequestInterceptor basicAuthRequestInterceptor() {
return new BasicAuthRequestInterceptor(clientId, clientSecret);
}
}
}
如果服務提供方需要OAuth2.0認證,可以使用spring-cloud-security中的OAuth2FeignRequestInterceptor。
注意事項
自己做Feign擴展和個性化使用時,有一些需要注意的事項,參考下文:
正確的使用方法和性能優化注意事項: http://tietang.wang/2016/09/06/%E5%BE%AE%E6%9C%8D%E5%8A%A1/Feign%E4%BD%BF%E7%94%A8%E6%80%A7%E8%83%BD%E4%BC%98%E5%8C%96/
參考文檔
FeignClient註解及參數: https://www.cnblogs.com/smiler/p/10689894.html
Spring Cloud中,如何使用Feign構造多參數的請求:https://www.jianshu.com/p/7ce46c0ebe9d
@FeignClient註解詳解: http://www.hxstrive.com/article/569.htm
使用Feign實現Form表單提交: https://www.jianshu.com/p/54b5e82a6d19
Feign實戰配置與詳細解析: https://my.oschina.net/u/3260714/blog/880050
聊聊feign的RequestInterceptor:https://juejin.im/post/5d2de4bc518825413a51ce4a