官方地址:https://cloud.spring.io/spring-cloud-static/Edgware.SR3/single/spring-cloud.html#spring-cloud-feign
一、概述
Feign是一個聲明式Web服務客戶端。它使編寫Web服務客戶端變得更容易。使用Feign創建一個接口並對其進行注釋。它具有可插入的注釋支持,包括Feign注釋和JAX-RS注釋。Feign還支持可插拔編碼器和解碼器。 Spring Cloud添加了對Spring MVC注釋的支持,並且使用了Spring Web中默認使用的相同HttpMessageConverters。Spring Cloud將Ribbon和Eureka集成在一起,在使用Feign時提供負載均衡的http客戶端。
源碼地址:https://github.com/OpenFeign/feign
1.1、基礎使用
1》添加pom
<dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-openfeign</artifactId> </dependency>
2》啟動類上添加注解
@SpringBootApplication @EnableFeignClients public class ComsumerMovieFeignApplication { public static void main(String[] args) { SpringApplication.run(ComsumerMovieFeignApplication.class, args); } }
3》添加一個接口並為接口添加注解,調用用戶服務
@FeignClient("microservice-provider-user") public interface UserFeignClient { // @GetMapping("/sample/{id}") @RequestMapping(method = RequestMethod.GET, value = "/movie/{id}") public User findById(@PathVariable("id") Long id); }
注意點:1、spring注解不能使用getMapping,需使用RequestMapping;2、@PathVariable必須添加參數;3、當服務接受參數是一個對象時候,此時默認會轉化為post請求,及時接口寫的是get請求【?待解決】
//請求不會成功,只要參數是復雜對象,即使指定了GET方法,feign依然會以post方法進行發送 @RequestMapping(method = RequestMethod.GET, value = "/get-user") public User getUser(User user);
4》程序調用
@Autowired private UserFeignClient userFeignClient; @GetMapping("/movie/{id}") public User findById(@PathVariable Long id) { return userFeignClient.findById(id); }
執行post類似
參考代碼:https://github.com/bjlhx15/spring-cloud/tree/master/microservice-comsumer-movie-feign
1.2、覆寫Feign的默認配置
1.2.1、概述
Spring Cloud的Feign支持中的一個中心概念是指定的客戶端。
每個feign客戶端都是整體的一部分,這些組件是一起工作以根據需要聯系遠程服務器,並且該組件具有一個名稱,開發人員可以使用@FeignClient批注命名。
Spring Cloud使用FeignClientsConfiguration創建一個新的集合,作為每個指定客戶端的ApplicationContext。這包含(除其他外)feign.Decoder,feign.Encoder和feign.Contract。
通過使用@FeignClient聲明額外配置(在FeignClientsConfiguration之上),Spring Cloud可讓您完全控制客戶端
示例
@FeignClient(name = "stores", configuration = FooConfiguration.class) public interface StoreClient { //.. }
注意事項:FooConfiguration
同RibbonConfiguration一致放包問題,參看:http://www.cnblogs.com/bjlhx/p/8859088.html
注意事項2:以前使用url可以不用,現在必須使用name
1.2.2、默認配置
Spring Cloud Netflix默認提供以下bean for feign(BeanType beanName:ClassName):
Decoder
feignDecoder:ResponseEntityDecoder
(which wraps aSpringDecoder
) 默認解碼Encoder
feignEncoder:SpringEncoder 默認編碼
Logger
feignLogger:Slf4jLogger 默認日志
Contract
feignContract:SpringMvcContract 默認契約
Feign.Builder
feignBuilder:HystrixFeign.Builder 默認構建builder
Client
feignClient: if Ribbon is enabled it is aLoadBalancerFeignClient
, otherwise the default feign client is used. 默認client
通過將feign.okhttp.enabled或feign.httpclient.enabled分別設置為true並將它們放在類路徑中,可以使用OkHttpClient和ApacheHttpClient feign客戶端。當使用Apache或OkHttpClient使用OK HTTP時,可以通過提供ClosableHttpClient的bean來定制HTTP客戶端。
1.2.3、非默認配置
Spring Cloud Netflix默認情況下不提供以下bean,但仍從應用程序上下文中查找這些類型的bean以創建假客戶端:
Logger.Level
Retryer
ErrorDecoder
Request.Options
Collection<RequestInterceptor>
SetterFactory
1.2.4、開發
編寫一個默認注解
@Configuration public class Configuration1 { @Bean public Contract feignContract() { return new feign.Contract.Default(); } }
因為原默認注解使用spring的現在這里改用feign契約,故以下調用需要使用feign的注解RequestLine等
編寫客戶端調用
@FeignClient(name = "microservice-provider-user", configuration = Configuration1.class) public interface UserFeignClient { @RequestLine("GET /sample/{id}") public User findById(@Param("id") Long id); }
程序使用即可。
參看代碼:https://github.com/bjlhx15/spring-cloud/tree/master/microservice-comsumer-movie-feign-customizing
1.2.5、如果請求eureka的接口如
@FeignClient(name = "xxxx", url = "http://localhost:8761/", configuration = Configuration2.class) public interface FeignClient2 { @RequestMapping(value = "/eureka/apps/{serviceName}") public String findServiceInfoFromEurekaByServiceName(@PathVariable("serviceName") String serviceName); }
因為eureka設置了權限此時訪問失敗
需增加配置類,Configuration2增加權限校驗
@Configuration public class Configuration2 { @Bean public BasicAuthRequestInterceptor basicAuthRequestInterceptor() { return new BasicAuthRequestInterceptor("user", "a123"); } }
1.2.6、Feign請求/響應壓縮
feign.compression.request.enabled=true feign.compression.response.enabled=true
Feign請求壓縮為您提供了類似於您為Web服務器設置的設置:
feign.compression.request.enabled=true feign.compression.request.mime-types=text/xml,application/xml,application/json feign.compression.request.min-request-size=2048
這些屬性使您可以選擇壓縮媒體類型和最小請求閾值長度。
1.3、feign日志
為每個創建的Feign客戶端創建一個記錄器。默認情況下,記錄器的名稱是用於創建Feign客戶端的接口的完整類名稱。 Feign日志記錄僅響應DEBUG級別。
application.yml.
logging.level.project.user.UserClient: DEBUG
注level是具體類路徑。可能不生效,需要配置一下配置
您可以為每個客戶端配置的Logger.Level對象告訴Feign要記錄多少。選擇是:
NONE
, No logging (DEFAULT).BASIC
, 只記錄請求方法和URL以及響應狀態碼和執行時間。HEADERS
, 記錄基本信息以及請求和響應標頭。FULL
, 為請求和響應記錄標題,正文和元數據。
例如,以下操作將Logger.Level設置為FULL:
@Configuration public class FooConfiguration { @Bean Logger.Level feignLoggerLevel() { return Logger.Level.FULL; } }
參看代碼:https://github.com/bjlhx15/spring-cloud/tree/master/microservice-comsumer-movie-feign-customizing
1.4、Feign第一次啟動timeout問題
hystrix默認1秒超時
方法一、可配置超時時間增加:
hystrix.command.default.execution.isolation.thread.timeoutInMilliseconds: 5000
方法二、關閉熔斷超時
hystrix.command.default.execution.timeout.enabled: false
方法三、關閉熔斷機制
feign.hystrix.enabled: false
可以參看:https://github.com/Netflix/Hystrix/wiki/Configuration
1.5、手動創建Feign客戶端

@Import(FeignClientsConfiguration.class) class FooController { private FooClient fooClient; private FooClient adminClient; @Autowired public FooController(Decoder decoder, Encoder encoder, Client client, Contract contract) { this.fooClient = Feign.builder().client(client) .encoder(encoder) .decoder(decoder) .contract(contract) .requestInterceptor(new BasicAuthRequestInterceptor("user", "user")) .target(FooClient.class, "http://PROD-SVC"); this.adminClient = Feign.builder().client(client) .encoder(encoder) .decoder(decoder) .contract(contract) .requestInterceptor(new BasicAuthRequestInterceptor("admin", "admin")) .target(FooClient.class, "http://PROD-SVC"); } }
1.6、feign源碼實現過程
1、首先通過@EnabledFeignClients注解開啟FeignClient的功能。主要是啟動程序時開啟對@FeignClient注解的包掃描
2、根據feign的規則實現接口,並在接口上面加上@FeignClient注解
3、程序啟動后,進行包掃描,掃描所有的@FeignClient的注解的類,並將這些類放入Ioc容器。
4、當接口的方法被調用時,通過JDK的代理來生成具體的RequestTemplate模板對象
5、根據RequestTemplate再生成Http請求的Request對象。
6、Request對象交給Client去處理,其中Client的網絡請求框架可以是HttpURLConnetion,HTTPClient和OkHttp等
7、最后Client被封裝到LoadBlanceClient類,這個類結合類Ribbon做負載均衡。