Spring Cloud微服務解決方案④:Feign的使用
Feign是一個宣告web服務客戶端,這便得編寫web服務客戶端更容易,使用Feign 建立一個介面並對它進行註解,它具有可插拔的註解支援包括Feign註解與JAX-RS註解,Feign還支援可插拔的編碼器與解碼器,Spring Cloud 增加了對 Spring MVC的註解,Spring Web 預設使用了HttpMessageConverters, Spring Cloud 整合 Ribbon 和 Eureka 提供的負載均衡的HTTP客戶端 Feign.
demo下載地址:https://download.csdn.net/download/qq_22075041/10851487在microservice-consumer-movie-feign模組裡面。
首先我們需要在pom上加Feign的依賴
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-feign</artifactId>
</dependency>
在啟動類上加一個註解@EnableFeignClients申明一下
然後就是關於服務呼叫了 如下:
package com.itmuch.cloud.feign; import org.springframework.cloud.netflix.feign.FeignClient; import org.springframework.web.bind.annotation.PathVariable; import org.springframework.web.bind.annotation.RequestBody; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestMethod; import com.itmuch.cloud.entity.User; //加一個註解,"microservice-provider-user"是服務的虛擬IP @FeignClient("microservice-provider-user") public interface UserFeignClient { @RequestMapping(value = "/simple/{id}", method = RequestMethod.GET) public User findById(@PathVariable("id") Long id); // 兩個坑:1. @GetMapping不支援 2. @PathVariable得設定value @RequestMapping(value = "/user", method = RequestMethod.POST) public User postUser(@RequestBody User user); // 該請求不會成功,只要引數是複雜物件,即使指定了是GET方法,feign依然會以POST方法進行傳送請求。可能是我沒找到相應的註解或使用方法錯誤。 @RequestMapping(value = "/get-user", method = RequestMethod.GET) public User getUser(User user); }
以上就是一個feign的簡單使用。注意他有幾個坑點。
下面我要自定義feign配置 怎麼做呢,原始碼對應microservice-consumer-movie-feign-customizing模組。
package com.itmuch.config; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import feign.Contract; import feign.Logger; @Configuration public class Configuration1 { @Bean public Contract feignContract() { return new feign.Contract.Default(); } @Bean Logger.Level feignLoggerLevel() { return Logger.Level.FULL;//控制檯會輸出debug日誌 } }
以上的程式碼 我們自定義了feign的Contract實現為fengin的預設實現,還有日誌級別(還需要在配置檔案中加如下一行程式碼)
//com.itmuch.cloud.feign.UserFeignClient類的日誌為debug
logging: level: com.itmuch.cloud.feign.UserFeignClient: DEBUG
注意上一篇文章講到的警告@Configuration註解不能放在@ComponentScan、@SpringBootApplication包以及子包下得問題,此處依然會存在,解決方案請看上一篇。
然後在UserFeignClient類上面的@FeignClient註解加一個屬性 configuration = Configuration1.class。
package com.itmuch.cloud.feign;
import org.springframework.cloud.netflix.feign.FeignClient;
import com.itmuch.cloud.entity.User;
import com.itmuch.config.Configuration1;
import feign.Param;
import feign.RequestLine;
@FeignClient(name = "microservice-provider-user", configuration = Configuration1.class)
public interface UserFeignClient {
//Configuration1類定義了feign的預設實現,他預設實現就是這麼寫的 下面倆行程式碼
@RequestLine("GET /simple/{id}")
public User findById(@Param("id") Long id);
}
以上就實現了feign的自定義配置。官方說的@FeignClient就是一個子容器(就像是Spring和SpringMVC容器的關係),當然裡面還還包含很多東西,感興趣自行研究。
但是有時候UserFeignClient類是這樣定義的,但是我UserFeignClient2、3、4的自定義配置不想用feign的剛才的配置啊,我又寫了一個Configuration2。加入了basic認證的bean。
package com.itmuch.config;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import feign.auth.BasicAuthRequestInterceptor;
@Configuration
public class Configuration2 {
@Bean
public BasicAuthRequestInterceptor basicAuthRequestInterceptor() {
return new BasicAuthRequestInterceptor("user", "password123");
}
}
然後看我的FeignClient2這樣寫:
package com.itmuch.cloud.feign;
import org.springframework.cloud.netflix.feign.FeignClient;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import com.itmuch.config.Configuration2;
@FeignClient(name = "xxxx", url = "http://localhost:8761/", configuration = Configuration2.class)
//xxxx就相當於http://localhost:8761/的別名
public interface FeignClient2 {
//注意下面我們使用的Contract實現是springMVC的實現 不再是feign的。
@RequestMapping(value = "/eureka/apps/{serviceName}")
public String findServiceInfoFromEurekaByServiceName(@PathVariable("serviceName") String serviceName);
}
除了此外feign還支援gzip等等,深入的話請檢視官方文件
題外話:有時候在第一次請求時報超時異常,是因為hystrix,他是一個斷路器,後面的文章會講到,他預設第一次響應時間超過1秒則中斷,那麼解決方案就是在配置檔案裡面延長他的響應時間,或者禁用超時,或者直接禁用hystrix。
# hystrix.command.default.execution.isolation.thread.timeoutInMilliseconds: 5000
# 或者:
# hystrix.command.default.execution.timeout.enabled: false
# 或者:
feign.hystrix.enabled: false ## 索性禁用feign的hystrix
# 超時的issue:https://github.com/spring-cloud/spring-cloud-netflix/issues/768
# 超時的解決方案: http://stackoverflow.com/questions/27375557/hystrix-command-fails-with-timed-out-and-no-fallback-available
# hystrix配置: https://github.com/Netflix/Hystrix/wiki/Configuration#execution.isolation.thread.timeoutInMilliseconds