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