1.Feign是什麼
Feign是一個聲明式WebService客戶端。使用Feign能讓編寫Web Service客戶端更加簡單,.它的使用方法是定義一個接口,然後在上面添加註解。
Spring Cloud對Feign進行了封裝,使其支持了Spring MVC標準註解和HttpMessageConverters。Feign可以與Eureka和Ribbon組合使用以支持負載均衡。
Feign的底層就是Ribbon
2.Feign能幹什麼
Feign旨在使編寫Java Http客戶端變得更容易。
封裝了Http調用流程,更適合面向接口化的變成習慣
前面在使用Ribbon+RestTemplate時,利用RestTemplate對http請求的封裝處理,形成了一套模版化的調用方法。但是在實際開發中,由於對服務依賴的調用可能不止一處,往往一個接口會被多處調用,所以通常都會針對每個微服務自行封裝一些客戶端類來包裝這些依賴服務的調用
所以,Feign在此基礎上做了進一步封裝,由他來幫助我們定義和實現依賴服務接口的定義。
在Feign的實現下,我們只需創建一個接口並使用註解的方式來配置它(以前是Dao接口上面標註Mapper註解,現在是一個微服務接口上面標註一個Feign註解即可),即可完成對服務提供方的接口綁定,簡化了使用Spring cloud Ribbon時,自動封裝服務調用客戶端的開發量。
3.Feign結合Ribbon
Spring Cloud集成了Ribbon和Eureka,可在使用Feign時提供負載均衡的http客戶端。
利用Ribbon維護了服務列表信息,並且通過輪詢實現了客戶端的負載均衡。而與Ribbon不同的是,通過feign只需要定義服務綁定接口且以聲明式的方法,優雅而簡單的實現了服務調用
4.Feign的設計流程
5.Feign的實踐
pom.xml文件
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-feign</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-eureka</artifactId>
</dependency>
Feign的底層是使用rabbon作爲負載均衡的客戶端,而ribbon的負載均衡依賴eureka 獲得各個服務的地址,所以如果想實現feign的負載均衡,要引入eureka。如果另有插件負責負載均衡,那可以不用引入。
主啓動類用@FeignClient和@EnableEurekaClient註釋
@SpringBootApplication
@EnableEurekaClient
@EnableFeignClients
public class Application
{
public static void main(String[] args)
{
SpringApplication.run(DeptConsumer80_Feign_App.class, args);
}
}
feign的配置,這一步非必要,如果想配置一些http相關字段,比如連接超時,讀取超時可以配置,除了下列屬性,還有其他相關屬性。請注意,如果你同時設置了rabbon和feign的配置,feign的配置會生效。如果你設置了@FeignClient註解的 url 參數,此時 ribbon 設置的超時時間將會失效,但是通過 Feign 設置的超時時間不會受到影響(仍然會生效)
application.yaml
feign:
client:
config:
default:
connectTimeout: 5000
readTimeout: 5000
loggerLevel: basic
Feign的使用
@FeignClient(value = "CART")
public interface CartFeignClient {
@PostMapping("/cart/{productId}")
Long addCart(@PathVariable("productId")Long productId);
}
如接口類一樣般聲明一個http接口,調用的時候按傳統的springbean注入就能調用了。此處是引用了eureka註冊的服務,feign將會去調用eureka註冊的。如果是沒有註冊中心,想像一個普通的http工具一樣的話,需要加上url屬性。
6.FeignClient註解的一些屬性
屬性名 | 默認值 | 作用 | 備註 |
---|---|---|---|
value | 空字符串 | 調用服務名稱,和name屬性相同 | |
serviceId | 空字符串 | 服務id,作用和name屬性相同 | 已過期 |
name | 空字符串 | 調用服務名稱,和value屬性相同 | |
url | 空字符串 | 全路徑地址或hostname,http或https可選 | |
decode404 | false | 配置響應狀態碼爲404時是否應該拋出FeignExceptions | |
configuration | {} | 自定義當前feign client的一些配置 | 參考FeignClientsConfiguration |
fallback | void.class | 熔斷機制,調用失敗時,走的一些回退方法,可以用來拋出異常或給出默認返回數據。 | 底層依賴hystrix,啓動類要加上@EnableHystrix |
path | 空字符串 | 自動給所有方法的requestMapping前加上前綴,類似與controller類上的requestMapping | |
primary | true |
7.Feign 自定義處理異常
feign可以自定義調用服務出錯的異常處理類,只要實現ErrorDecoder類的decode方法,然後在application配置類配置上該類是feign的異常處理類即可
public class FeignDefaultErrorDecoder implements ErrorDecoder {
public Exception decode(String methodKey, Response response) {
String body = "";
ErrorResponseBean standard = null;
try {
if (response.body() != null) {
body = Util.toString(response.body().asReader());
standard = JsonUtils.parseJson(body, ErrorResponseBean.class);
}
} catch (Exception ignored) {
}
String msg = String.format("status %s reading %s", new Object[]{Integer.valueOf(response.status()), methodKey});
msg += "; content:\n" + body;
return new UnexpectedErrorResponse(msg, ImmutableMap.of("response", response, "status", response.status(), "content", body));
}
}
配置類
feign.client.config.default.error-decoder=com.metals.user.config.web.FeignDefaultErrorDecoder
8.Feign底層支持的客戶端
feign底層支持三種客戶端,每種客戶端都對應這feign在進行http請求時採用的不同客戶端請求方式。除了這三種,還有一個客戶端是這三種的包裝。
- Client.Default
Feign 的默認的客戶端,如果沒有特別指定,將會是這個。內部使用JDK的HttpURLConnnection 來處理 HTTP URL 的請求 - .HttpClient(ApacheHttpClient)
Feign 將會通過 feign.httpclient.ApacheHttpClient(基於 Apache httpclient 開源組件) 來處理 HTTP URL 的請求 - OkHttpClient
Feign 將會通過 feign.okhttp.OkHttpClient(基於 Okhttp3 開源組件)來處理 HTTP URL 的請求 - LoadBalancerFeignClient
該類作爲 Client.Default、ApacheHttpClient、OkHttpClient 的包裝類而存在,內部使用 Ribbon 負載均衡算法獲取 server 服務器,可以理解 Feign 是通過該類的 LoadBalancerFeignClient.execute(Request request, Options options) 方法將請求轉發給真正的客戶端(Client.Default、ApacheHttpClient、OkHttpClient)來完成對 HTTP URL 請求的處理
feign的自動配置類有FeignRibbonClientAutoConfiguration和OkHttpFeignLoadBalancedConfiguration等等
9.使用OKhttp發送request
前面說到feign底層有不同客戶端,可以通過配置來切換,這裏以okhttp爲例
maven導入okhttp
<dependency>
<groupId>io.github.openfeign</groupId>
<artifactId>feign-okhttp</artifactId>
</dependency>
application配置類
feign.httpclient.enabled=false
feign.okhttp.enabled=true
定義一個配置類
@Configuration
@ConditionalOnClass(Feign.class)
@AutoConfigureBefore(FeignAutoConfiguration.class)
public class FeignOkHttpConfig {
@Bean
public okhttp3.OkHttpClient okHttpClient(){
return new okhttp3.OkHttpClient.Builder()
.readTimeout(60, TimeUnit.SECONDS)
.connectTimeout(60, TimeUnit.SECONDS)
.writeTimeout(120, TimeUnit.SECONDS)
.connectionPool(new ConnectionPool())
.build();
}
}
10.Feign原理簡述
- 啓動時,程序會進行包掃描,掃描所有包下所有@FeignClient註解的類,並將這些類注入到spring的IOC容器中。當定義的Feign中的接口被調用時,通過JDK的動態代理來生成RequestTemplate。
- RequestTemplate中包含請求的所有信息,如請求參數,請求URL等。
- RequestTemplate生成Request,然後將Request交給client處理,這個client默認是JDK的HTTPUrlConnection,也可以是OKhttp、Apache的HTTPClient等。
- 最後client封裝成LoadBaLanceClient,結合ribbon負載均衡地發起調用。
11.Feign Client的配置方式
方式一,如上面那樣,可以直接配置在application配置文件
feign:
client:
config:
default:
connectTimeout: 5000 #連接超時
readTimeout: 5000 #讀取超時
loggerLevel: basic #日誌等級
方式二,通過配置類去綁定
@EnableFeignClients註解上有個defaultConfiguration屬性,可以指定默認Feign Client的配置類
@EnableFeignClients(defaultConfiguration = DefaultFeignConfiguration.class)
@EnableDiscoveryClient
@SpringBootApplication
public class ProductApplication {
public static void main(String[] args) {
SpringApplication.run(ProductApplication.class, args);
}
}
DefaultFeignConfiguration內容:
@Configuration
public class DefaultFeignConfiguration {
@Bean
public Retryer feignRetryer() {
return new Retryer.Default(1000,3000,3);
}
}
11.Feign Client的開啓日誌
正常的系統需要日誌去維護,對於一個服務,想要知道調用日誌流程可以有兩種方式,一種是傳統的interceptor+spring的HttpMessageConverter,可以得到這個服務被人調用和返回的流程日誌。對於feign來說,可以配置開啓日誌,能直接看到這個服務調用別的服務的相關日誌。
這種開啓feign配置的方式有兩種,與上面差不多,一種配置類,一種配置文件
1.配置類
@Configuration
public class DefaultFeignConfiguration {
@Bean
public Logger.Level feignLoggerLevel(){
return Logger.Level.BASIC;
}
}
2.配置文件
logging:
level:
com.xt.open.jmall.product.remote.feignclients.CartFeignClient: debug
12.OpenFeign和Feign
對於openFeign和feign在學習中是疑惑最大的點,其實咱們現在通常使用的都是openFeign。
Ribbon
Ribbon 是 Netflix開源的基於HTTP和TCP等協議負載均衡組件
Ribbon 可以用來做客戶端負載均衡,調用註冊中心的服務
Ribbon的使用需要代碼裏手動調用目標服務,使用比較繁瑣的RestTemplate
Feign
一個輕量級RESTful的HTTP服務客戶端
Feign內置了Ribbon,用來做客戶端負載均衡,去調用服務註冊中心的服務。
Feign的使用方式是:使用Feign的註解定義接口,調用這個接口,就可以調用服務註冊中心的服務
請注意!!Feign本身不支持Spring MVC的註解,它有一套自己的註解,是Feign的特有註解來定義接口,而這套已經停止更新了
OpenFeign
在feign的基礎上支持了springMVC的註解,也就是@RequestMapping等等。OpenFeign的@FeignClient可以解析SpringMVC的@RequestMapping註解下的接口,並通過動態代理的方式產生實現類,實現類中做負載均衡並調用其他服務。