您好,登錄后才能下訂單哦!
本篇內(nèi)容主要講解“如何深入學(xué)習(xí)SpringCloud Fegin”,感興趣的朋友不妨來看看。本文介紹的方法操作簡單快捷,實用性強。下面就讓小編來帶大家學(xué)習(xí)“如何深入學(xué)習(xí)SpringCloud Fegin”吧!
在我們平時的工作中,我們經(jīng)常會遇到要調(diào)用內(nèi)部API或者其他第三方服務(wù)的API,在遇到Fegin之前我們基本會使用以下幾種方式。
1.HttpURLConnection
簡介:
URLConnection是個抽象類,它有兩個直接子類分別是HttpURLConnection和JarURLConnection。
另外一個重要的類是URL,通常URL可以通過傳給構(gòu)造器一個String類型的參數(shù)來生成一個指向特定地址的URL實例。
每個 HttpURLConnection 實例都可用于生成單個請求,但是其他實例可以透明地共享連接到 HTTP 服務(wù)器的基礎(chǔ)網(wǎng)絡(luò)。
請求后在 HttpURLConnection 的 InputStream 或 OutputStream 上調(diào)用 close() 方法可以釋放與此實例關(guān)聯(lián)的網(wǎng)絡(luò)資源,但對共享的持久連接沒有任何影響。
如果在調(diào)用 disconnect() 時持久連接空閑,則可能關(guān)閉基礎(chǔ)套接字。
任何網(wǎng)絡(luò)連接都需要經(jīng)過socket才能連接,HttpURLConnection不需要設(shè)置socket,所以,HttpURLConnection并不是底層的連接,而是在底層連接上的一個請求。
這就是為什么HttpURLConneciton只是一個抽象類,自身不能被實例化的原因。HttpURLConnection只能通過URL.openConnection()方法創(chuàng)建具體的實例。
雖然底層的網(wǎng)絡(luò)連接可以被多個HttpURLConnection實例共享,但每一個HttpURLConnection實例只能發(fā)送一個請求。
請求結(jié)束之后,應(yīng)該調(diào)用HttpURLConnection實例的InputStream或OutputStream的close()方法以釋放請求的網(wǎng)絡(luò)資源,不過這種方式對于持久化連接沒用。對于持久化連接,得用disconnect()方法關(guān)閉底層連接的socket。
HttpURLConnection請求響應(yīng)流程:
2.HttpClient
簡介:
HttpClient是Apache Jakarta Common 下的子項目,可以用來提供高效的、最新的、功能豐富的支持 HTTP 協(xié)議的客戶端編程工具包,并且它支持 HTTP 協(xié)議最新的版本和建議。
它是一個HTTP通信庫、一個工具包,因此它只提供一個通用瀏覽器應(yīng)用程序所期望的功能子集。
HttpClient與瀏覽器最根本的區(qū)別是:HttpClient中沒有用戶界面,瀏覽器需要一個渲染引擎來顯示頁面,并解釋用戶輸入(例如鼠標(biāo)點擊顯示頁面上的某處之后如何響應(yīng)、計算如何顯示HTML頁面、級聯(lián)樣式表和圖像、javascript解釋器運行嵌入HTML頁面或從HTML頁面引用的javascript代碼、來自用戶界面的事件被傳遞到j(luò)avascript解釋器進行處理等等等等)。
HttpClient只能以編程的方式通過其API用于傳輸和接受HTTP消息,它對內(nèi)容也是完全不可知的。
HttpClient還是有很多好的特點(摘自Apache HttpClient官網(wǎng)):
1.基于標(biāo)準(zhǔn)、純凈的java語言。實現(xiàn)了HTTP1.0和HTTP1.1;
2.以可擴展的面向?qū)ο蟮慕Y(jié)構(gòu)實現(xiàn)了HTTP全部的方法(GET, POST等7種方法);
3.支持HTTPS協(xié)議;
4.通過HTTP代理建立透明的連接;
5.利用CONNECT方法通過HTTP代理建立隧道的HTTPS連接;
6.Basic, Digest, NTLMv1, NTLMv2, NTLM2 Session, SNPNEGO/Kerberos認(rèn)證方案;
7.插件式的自定義認(rèn)證方案;
8.便攜可靠的套接字工廠使它更容易的使用第三方解決方案;
9.連接管理器支持多線程應(yīng)用;支持設(shè)置最大連接數(shù),同時支持設(shè)置每個主機的最大連接數(shù),發(fā)現(xiàn)并關(guān)閉過期的連接;
10.自動處理Set-Cookie中的Cookie;
11.插件式的自定義Cookie策略;
12.Request的輸出流可以避免流中內(nèi)容直接緩沖到socket服務(wù)器;
13.Response的輸入流可以有效的從socket服務(wù)器直接讀取相應(yīng)內(nèi)容;
14.在HTTP1.0和HTTP1.1中利用KeepAlive保持持久連接;
15.直接獲取服務(wù)器發(fā)送的response code和 headers;
16.設(shè)置連接超時的能力;
17.實驗性的支持HTTP1.1 response caching;
18.源代碼基于Apache License 可免費獲取。
Get Demo
public static void main(String[] args) throws IOException { //1.打開瀏覽器 CloseableHttpClient httpClient = HttpClients.createDefault(); //2.聲明get請求 HttpGet httpGet = new HttpGet("http://www.baidu.com/s?wd=java"); //3.發(fā)送請求 CloseableHttpResponse response = httpClient.execute(httpGet); //4.判斷狀態(tài)碼 if(response.getStatusLine().getStatusCode()==200){ HttpEntity entity = response.getEntity(); //使用工具類EntityUtils,從響應(yīng)中取出實體表示的內(nèi)容并轉(zhuǎn)換成字符串 String string = EntityUtils.toString(entity, "utf-8"); System.out.println(string); } //5.關(guān)閉資源 response.close(); httpClient.close(); }
Post Demo
public static void main(String[] args) throws IOException { //1.打開瀏覽器 CloseableHttpClient httpClient = HttpClients.createDefault(); //2.聲明get請求 HttpPost httpPost = new HttpPost("https://www.oschina.net/"); //3.開源中國為了安全,防止惡意攻擊,在post請求中都限制了瀏覽器才能訪問 httpPost.addHeader("User-Agent","Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/68.0.3440.106 Safari/537.36"); //4.判斷狀態(tài)碼 List<NameValuePair> parameters = new ArrayList<NameValuePair>(0); parameters.add(new BasicNameValuePair("scope", "project")); parameters.add(new BasicNameValuePair("q", "java")); UrlEncodedFormEntity formEntity = new UrlEncodedFormEntity(parameters,"UTF-8"); httpPost.setEntity(formEntity); //5.發(fā)送請求 CloseableHttpResponse response = httpClient.execute(httpPost); if(response.getStatusLine().getStatusCode()==200){ HttpEntity entity = response.getEntity(); String string = EntityUtils.toString(entity, "utf-8"); System.out.println(string); } //6.關(guān)閉資源 response.close(); httpClient.close(); }
3.OKHttp
給大家推薦一篇文章,個人覺得寫得很好。
https://blog.csdn.net/iispring/article/details/51661195?utm_medium=distribute.pc_relevant.none-task-blog-BlogCommendFromMachineLearnPai2-3.channel_param&depth_1-utm_source=distribute.pc_relevant.none-task-blog-BlogCommendFromMachineLearnPai2-3.channel_param
4.RestTemplate
簡介:
RestTemplate 是從 Spring3.0 開始支持的一個 HTTP 請求工具,它提供了常見的REST請求方案的模版,例如 GET 請求、POST 請求、PUT 請求、DELETE 請求以及一些通用的請求執(zhí)行方法 exchange 以及 execute。
RestTemplate 繼承自 InterceptingHttpAccessor 并且實現(xiàn)了 RestOperations 接口,其中 RestOperations 接口定義了基本的 RESTful 操作,這些操作在 RestTemplate 中都得到了實現(xiàn)。接下來我們就來看看這些操作方法的使用。
Get Demo
public void doHttpGetTest() throws UnsupportedEncodingException { // -------------------------------> 獲取Rest客戶端實例 RestTemplate restTemplate = new RestTemplate(); // -------------------------------> 解決(響應(yīng)數(shù)據(jù)可能)中文亂碼 的問題 List<HttpMessageConverter<?>> converterList = restTemplate.getMessageConverters(); converterList.remove(1); // 移除原來的轉(zhuǎn)換器 // 設(shè)置字符編碼為utf-8 HttpMessageConverter<?> converter = new StringHttpMessageConverter(StandardCharsets.UTF_8); converterList.add(1, converter); // 添加新的轉(zhuǎn)換器(注:convert順序錯誤會導(dǎo)致失敗) restTemplate.setMessageConverters(converterList); // -------------------------------> (選擇性設(shè)置)請求頭信息 // HttpHeaders實現(xiàn)了MultiValueMap接口 HttpHeaders httpHeaders = new HttpHeaders(); // 給請求header中添加一些數(shù)據(jù) httpHeaders.add("Java 學(xué)習(xí)部落", "這是一個學(xué)習(xí)技術(shù)的公眾號!"); // -------------------------------> 注:GET請求 創(chuàng)建HttpEntity時,請求體傳入null即可 // 請求體的類型任選即可;只要保證 請求體 的類型與HttpEntity類的泛型保持一致即可 String httpBody = null; HttpEntity<String> httpEntity = new HttpEntity<String>(httpBody, httpHeaders); // -------------------------------> URI StringBuffer paramsURL = new StringBuffer("http://127.0.0.1:8080/restTemplate/doHttpGet"); // 字符數(shù)據(jù)最好encoding一下;這樣一來,某些特殊字符才能傳過去(如:flag的參數(shù)值就是“&”,不encoding的話,傳不過去) paramsURL.append("?flag=" + URLEncoder.encode("&", "utf-8")); URI uri = URI.create(paramsURL.toString()); // -------------------------------> 執(zhí)行請求并返回結(jié)果 // 此處的泛型 對應(yīng) 響應(yīng)體數(shù)據(jù) 類型; // 即:這里指定響應(yīng)體的數(shù)據(jù)裝配為String ResponseEntity<String> response = restTemplate.exchange(uri, HttpMethod.GET, httpEntity, String.class); // -------------------------------> 響應(yīng)信息 //響應(yīng)碼,如:401、302、404、500、200等 System.err.println(response.getStatusCodeValue()); Gson gson = new Gson(); // 響應(yīng)頭 System.err.println(gson.toJson(response.getHeaders())); // 響應(yīng)體 if(response.hasBody()) { System.err.println(response.getBody()); } }
Post Demo
public void doHttpPostTest() throws UnsupportedEncodingException { // 獲取Rest客戶端實例 RestTemplate restTemplate = new RestTemplate(); // 解決(響應(yīng)數(shù)據(jù)可能)中文亂碼 的問題 List<HttpMessageConverter<?>> converterList = restTemplate.getMessageConverters(); converterList.remove(1); // 移除原來的轉(zhuǎn)換器 // 設(shè)置字符編碼為utf-8 HttpMessageConverter<?> converter = new StringHttpMessageConverter(StandardCharsets.UTF_8); // 添加新的轉(zhuǎn)換器(注:convert順序錯誤會導(dǎo)致失敗) converterList.add(1, converter); restTemplate.setMessageConverters(converterList); // (選擇性設(shè)置)請求頭信息 // HttpHeaders實現(xiàn)了MultiValueMap接口 HttpHeaders httpHeaders = new HttpHeaders(); // 設(shè)置contentType httpHeaders.setContentType(MediaType.APPLICATION_JSON_UTF8); // 給請求header中添加一些數(shù)據(jù) httpHeaders.add("Java 學(xué)習(xí)部落", "這是一個學(xué)習(xí)java的公眾號 !"); // 將請求頭、請求體數(shù)據(jù),放入HttpEntity中 // 請求體的類型任選即可;只要保證 請求體 的類型與HttpEntity類的泛型保持一致即可 // 這里手寫了一個json串作為請求體 數(shù)據(jù) (實際開發(fā)時,可使用fastjson、gson等工具將數(shù)據(jù)轉(zhuǎn)化為json串) String httpBody = "{\"motto\":\"java真強大啊 !\"}"; HttpEntity<String> httpEntity = new HttpEntity<String>(httpBody, httpHeaders); // URI StringBuffer paramsURL = new StringBuffer("http://127.0.0.1:8080/restTemplate/doHttpPost"); // 字符數(shù)據(jù)最好encoding一下;這樣一來,某些特殊字符才能傳過去(如:flag的參數(shù)值就是“&”,不encoding的話,傳不過去) paramsURL.append("?flag=" + URLEncoder.encode("&", "utf-8")); URI uri = URI.create(paramsURL.toString()); // 執(zhí)行請求并返回結(jié)果 // 此處的泛型 對應(yīng) 響應(yīng)體數(shù)據(jù) 類型;即:這里指定響應(yīng)體的數(shù)據(jù)裝配為String ResponseEntity<String> response = restTemplate.exchange(uri, HttpMethod.POST, httpEntity, String.class); // 響應(yīng)信息 //響應(yīng)碼,如:401、302、404、500、200等 System.err.println(response.getStatusCodeValue()); Gson gson = new Gson(); // 響應(yīng)頭 System.err.println(gson.toJson(response.getHeaders())); // 響應(yīng)體 if(response.hasBody()) { System.err.println(response.getBody()); }}
此處只是簡單介紹下RestTemplate的Get請求和Post請求,并未深入探討RestTemplate,以及實現(xiàn)RestTemplate的其它形式的請求。
因為我已經(jīng)迫不及待的想和Fegin來一個美麗的邂逅了。
什么是Fegin?
Feign是Netflix開發(fā)的聲明式、模板化的HTTP客戶端, Feign可以幫助我們更快捷、優(yōu)雅地調(diào)用HTTP API。
在Spring Cloud中,使用Feign非常簡單:創(chuàng)建一個接口,并在接口上添加一些注解,代碼就完成了。Feign支持多種注解,例如Feign自帶的注解或者JAX-RS注解等。
Spring Cloud對Feign進行了增強,使Feign支持了Spring MVC注解,并整合了Ribbon和Eureka,從而讓Feign的使用更加方便。
Spring Cloud Feign是基于Netflix feign實現(xiàn),整合了Spring Cloud Ribbon和Spring Cloud Hystrix,除了提供這兩者的強大功能外,還提供了一種聲明式的Web服務(wù)客戶端定義的方式。
Spring Cloud Feign幫助我們定義和實現(xiàn)依賴服務(wù)接口的定義。在Spring Cloud feign的實現(xiàn)下,只需要創(chuàng)建一個接口并用注解方式配置它,即可完成服務(wù)提供方的接口綁定,簡化了在使用Spring Cloud Ribbon時自行封裝服務(wù)調(diào)用客戶端的開發(fā)量。
Spring Cloud Feign具備可插拔的注解支持,支持Feign注解、JAX-RS注解和Spring MVC的注解。
Feign實際上是對普通HTTP客戶端的一層封裝,其目的是降低集成成本、提升可靠性。Feign支持三種HTTP客戶端,包括JDK自帶的HttpURLConnection、Apache HttpClient和Square OkHttp,默認(rèn)使用Apache HttpClient。
Fegin有什么作用?
Feign可以把Rest的請求進行隱藏,偽裝成類似SpringMVC的Controller一樣。
你不用再自己拼接url,拼接參數(shù)等等操作,一切都交給Feign去做。
在這個時間節(jié)點上,很多人對這“兩種”Feign傻傻分不清楚,不知有何區(qū)別和聯(lián)系,本文將給與告知。首先需要明確:他倆是屬于同一個東西,Feign屬于Netflix
開源的組件。針對于于差異性,下面分這幾個方面展開做出對比
1、GAV坐標(biāo)差異:
<dependency><groupId>com.netflix.feign</groupId><artifactId>feign-core</artifactId></dependency><dependency><groupId>io.github.openfeign</groupId><artifactId>feign-core</artifactId></dependency>
2、官網(wǎng)地址差異:https://github.com/Netflix/feign
和https://github.com/OpenFeign/feign
。不過現(xiàn)在訪問https://github.com/Netflix/feign
已經(jīng)被重定向到了后者上。
3、發(fā)版歷史:
Netflix Feign1.0.0
發(fā)布于2013.6,于2016.7月發(fā)布其最后一個版本8.18.0
Open Feign:首個版本便是9.0.0
版,于2016.7月發(fā)布,然后一直持續(xù)發(fā)布到現(xiàn)在(未停止)
從以上3個特點其實你可以很清楚的看到兩者的區(qū)別和聯(lián)系,簡單的理解:Netflix Feign
僅僅只是改名成為了Open Feign
而已,然后Open Feign項目在其基礎(chǔ)上繼續(xù)發(fā)展至今。
9.0版本之前它叫Netflix Feign,自9.0版本起它改名叫Open Feign了。
但是請注意,雖然GAV完全變了,但是源碼的包名和核心API是沒有任何變化的,所以扔具有很好的向下兼容性(并不是100%向下兼容)。
他倆的差異類似于上述描述的差異,也從幾個方面說明:
1、GAV坐標(biāo)差異:
<dependency><groupId>org.springframework.cloud</groupId><artifactId>spring-cloud-starter-feign</artifactId></dependency><dependency><groupId>org.springframework.cloud</groupId><artifactId>spring-cloud-starter-openfeign</artifactId></dependency>
發(fā)版歷史:
spring-cloud-starter-feign:2015.3發(fā)布1.0.0版本,2019.5.23發(fā)布器最后一個版本1.4.7.RELEASE
值得注意的是,從1.4.0.RELEASE
開始,它的1.4.x的發(fā)版軌跡完全同下的1.4.x的發(fā)版軌跡
spring-cloud-starter-openfeign:2017.11發(fā)布其首個版本,版本號為:1.4.0.RELEASE
?,F(xiàn)在仍持續(xù)更新中,當(dāng)下最新版為2.2.1.RELEASE
說明:1.4.7.RELEASE是整個Spring Cloud1.x關(guān)于Feign方面的最終版本,2.x版本還在持續(xù)維護更新中
注意:老的spring-cloud-starter-feign 從1.2.0.RELEASE
開始 已放棄Netflix feign而全面使用更新的Open Feign版本,而spring-cloud-starter-openfeign更是和Netflix Feign已經(jīng)沒有關(guān)系了。
對于版本,可粗略的理解為:spring-cloud-starter-openfeign
是為Spring Cloud2.x準(zhǔn)備的,只不過維持了一段時間的對1.x的兼容。而spring-cloud-starter-feign
是專為Spring Cloud1.x服務(wù)。
核心API包名:Spring Cloud的大版本升級具有向下不兼容性,這也體現(xiàn)在了Feign上:
@FeignClient注解:
說明:這里的1.x不僅僅指的feign,還包括openfeign的1.4.x版本哦
1.x版本包名是org.springframework.cloud.netflix.feign.FeignClient
,所在Jar是spring-cloud-netflix-core
2.x版本包名是org.springframework.cloud.openfeign.FeignClient
,所在Jar是spring-cloud-openfeign-core
@EnableFeignClients注解:差異同上
----引自:https://cloud.tencent.com/developer/article/1588509
Fegin 的九大組件
1.注解翻譯器 Contract
我們都知道,在 Feign 中可以通過定義 API 接口的方式來調(diào)用遠(yuǎn)程的 Http API,在定義調(diào)用 Client 的時候需要增加一些注解來描述這個調(diào)用 API 的基本信息,比如請求類型是 GET 還是 POST,請求的 URI 是什么。
Contract 允許用戶自定義注解翻譯器去解析注解信息。
Contract 決定了哪些注解可以標(biāo)注在接口/接口方法上是有效的,并且提取出有效的信息,組裝成為MethodMetadata元信息。
最典型的應(yīng)用場景就是在 Spring Cloud 中使用 Feign,我們可以使用 Spring MVC 的注解來定義 Feign 的客戶端,就是因為 Spring Cloud OpenFeign 中實現(xiàn)了自己的 SpringMvcContract。
2.Encoder 編碼器
將我們的請求信息通過指定的編碼方式進行編碼到Http請求體中進行傳輸。
3.QueryMapEncoder 參數(shù)查詢編碼器
QueryMapEncoder 是針對實體類參數(shù)查詢的編碼器,可以基于 QueryMapEncoder 將實體類生成對應(yīng)的查詢參數(shù)。
4.Decoder 解碼器
Decoder 解碼器作用于Response,用于解析Http請求的響應(yīng),提取有用信息數(shù)據(jù)。
Decoder 解碼器將HTTP響應(yīng)feign.Response
解碼為指定類型的單一對象。
5.ErrorDecoder 錯誤解碼器
ErrorDecoder 錯誤解碼器是在發(fā)生錯誤、異常情況時使用的解碼器,允許你對異常進行特殊處理。
6.Logger 日志記錄
Feign自己抽象出來的一個日志記錄器,負(fù)責(zé) Feign 中記錄日志的,可以指定 Logger 的級別以及自定義日志的輸出。
7.Client 請求執(zhí)行組件
Client 是負(fù)責(zé) HTTP 請求執(zhí)行的組件,F(xiàn)eign 將請求信息封裝好后會交由 Client 來執(zhí)行。
默認(rèn)情況下,服務(wù)之間調(diào)用使用的HttpURLConnection,沒有使用連接池,每次使用都會創(chuàng)建HttpURLConnection連接,效率非常低。
為了通過連接池提高效率,我們可以使用appache httpclient做為連接池。當(dāng)然了配置OkHttpClient連接池,也是類似的方法。
8.Retryer 重試組件
重試并不是報錯以后的重試,而是負(fù)載均衡客戶端發(fā)現(xiàn)遠(yuǎn)程請求實例不可到達(dá)后,去重試請求其他實例。
Feign本身也具備重試能力,在早期的Spring Cloud中,F(xiàn)eign使用的是 feign.Retryer.Default#Default() ,重試5次。
但Feign整合了Ribbon,Ribbon也有重試的能力,此時,就可能會導(dǎo)致行為的混亂。
Spring Cloud意識到了此問題,因此做了改進,將Feign的重試改為 feign.Retryer#NEVER_RETRY ,如需使用Feign的重試,只需使用Ribbon的重試配置即可。
9.RequestInterceptor 請求攔截器
我們可以通過實現(xiàn)RequestInterceptor接口的apply方法,在請求執(zhí)行前設(shè)置一些擴展的參數(shù)信息或者是修改請求頭信息,因為feign在發(fā)送請求之前都會調(diào)用該接口的apply方法,所以我們也可以通過實現(xiàn)該接口來記錄請求發(fā)出去的時間點。
Fegin 的執(zhí)行過程
Fegin的原生API的使用
public interface GitHub { @RequestLine("GET /repos/{owner}/{repo}/contributors") List<Contributor> contributors(@Param("owner") String owner, @Param("repo") String repository); class Contributor { String login; int contributions; }}public class MyApp { public static void main(String[] args) { GitHub github = Feign.builder() .decoder(new GsonDecoder()) .target(GitHub.class, "https://api.github.com"); /* The owner and repository parameters will be used to expand the owner and repo expressions * defined in the RequestLine. * * the resulting uri will be https://api.github.com/repos/OpenFeign/feign/contributors */ github.contributors("OpenFeign", "feign"); }}
這段代碼是我從 OpenFeign 的 GitHub 主頁上示例代碼。
這是一個 GET 請求的示列,定義了一個 GitHub 的接口,接口中定義了一個查詢的方法和參數(shù)。在方法上有 @RequestLine 注解,定義了請求類型和請求的 URI,URI 中有對應(yīng)的參數(shù)占位符,返回值是集合,集合中是對應(yīng)的返回結(jié)構(gòu)對象。
我們通過 Feign 的 builder 模式構(gòu)建了 GitHub 接口對象后,就可以直接通過 GiuHub 接口對象調(diào)用里面的 contributors 方法,然后可以得到返回結(jié)果。Feign 的這種方式就跟 Dubbo 中的調(diào)用方式是一樣的,就像調(diào)用本地方法一樣。
使用原生的 Feign 來調(diào)用 API,只需要通過特定的注解來描述調(diào)用的 API 信息,這些信息的請求方式可以是 GET 或者 POST 等,請求參數(shù)是什么?請求的地址是什么? 把這些信息定義好后就可以直接使用這個定好了的接口來調(diào)用對應(yīng)的遠(yuǎn)程 API。
Fegin結(jié)合SpringCloud使用
1.首先創(chuàng)建一個OpenFeginClient模塊,pom.xml代碼如下:
<dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-netflix-eureka-server</artifactId> </dependency> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-openfeign</artifactId> </dependency>
2.在啟動類上添加 @EnableFeignClients 啟用 Feign
package com.javaer.study.openfeginclient;import org.springframework.boot.SpringApplication;import org.springframework.boot.autoconfigure.SpringBootApplication;import org.springframework.cloud.netflix.eureka.EnableEurekaClient;import org.springframework.cloud.openfeign.EnableFeignClients;/** * @Author 公眾號【Java學(xué)習(xí)部落】 * * 關(guān)注公眾號獲取4000G精品視頻資源 * * 更有更多學(xué)習(xí)Java后端、中間件,大數(shù)據(jù)、微服務(wù)、分布式、大數(shù)據(jù)等學(xué)習(xí)干貨 **/@SpringBootApplication@EnableFeignClients@EnableEurekaClientpublic class OpenfeginclientApplication { public static void main(String[] args) { SpringApplication.run(OpenfeginclientApplication.class, args); }}
server: port: 8888spring: application: name: spring-cloud-feign-openClienteureka: client: service-url: defaultZone: http://localhost:8761/eureka/
package com.javaer.study.openfeginclient;import org.springframework.cloud.openfeign.FeignClient;import org.springframework.web.bind.annotation.RequestMapping;import org.springframework.web.bind.annotation.RequestMethod;import org.springframework.web.bind.annotation.RequestParam;/** * 一個可以調(diào)用的客戶端 * * @author topJavaer * 公眾號:【Java學(xué)習(xí)部落】 * @create 2020 11 10 * @Version 1.0.0 *///@FeignClient 即是指定客戶端信息注解,務(wù)必聲明在接口上面,url手動指定了客戶端的接口地址@FeignClient(name = "github-client", url = "https://api.github.com")public interface GitHubApiClient { @RequestMapping(value = "/search/repositories", method = RequestMethod.GET) String searchRepositories(@RequestParam("q") String queryStr);}
5.添加測試代碼
package com.javaer.study.openfeginclient;import org.springframework.web.bind.annotation.RequestMapping;import org.springframework.web.bind.annotation.RequestParam;import org.springframework.web.bind.annotation.RestController;import javax.annotation.Resource;/** * 測試類 * * @author topJavaer * 公眾號:【Java學(xué)習(xí)部落】 * @create 2020 11 10 * @Version 1.0.0 */@RestControllerpublic class GitHubApiTest { @Resource private GitHubApiClient gitHubApiClient; @RequestMapping("/search/github/repository") public String searchGithubRepositoryByName(@RequestParam("name") String repositoryName) { return gitHubApiClient.searchRepositories(repositoryName); }}
6.最后我們啟動之前再講述Eureka時編寫的Eureka Server,然后啟動該模塊。
訪問:http://localhost:8888/search/github/repository?name=spring-cloud-dubbo
得到如下結(jié)果:
上述就是Spring Cloud 使用OpenFegin的基本流程,是不是很簡單,看一眼,操作一遍,立馬就會了,當(dāng)然了,如果說想要深入了解,僅僅這樣是遠(yuǎn)遠(yuǎn)不夠的,還是需要大家自己繼續(xù)去專研,去深入探究。
Fegin的核心注解@FeignClient詳解
package org.springframework.cloud.netflix.feign; import java.lang.annotation.Documented; import java.lang.annotation.ElementType; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target; import org.springframework.core.annotation.AliasFor; @Target(ElementType.TYPE) @Retention(RetentionPolicy.RUNTIME) @Documented public @interface FeignClient { @AliasFor("name") String value() default ""; @Deprecated String serviceId() default ""; @AliasFor("value") String name() default ""; String qualifier() default ""; String url() default ""; boolean decode404() default false; Class<?>[] configuration() default {}; Class<?> fallback() default void.class; Class<?> fallbackFactory() default void.class; String path() default ""; boolean primary() default true; }
name: 指定Feign Client的名稱,如果項目使用了 Ribbon,name屬性會作為微服務(wù)的名稱,用于服務(wù)發(fā)現(xiàn)。
serviceId: 用serviceId做服務(wù)發(fā)現(xiàn)已經(jīng)被廢棄,所以不推薦使用該配置。
value: 指定Feign Client的serviceId,如果項目使用了 Ribbon,將使用serviceId用于服務(wù)發(fā)現(xiàn),但上面可以看到serviceId做服務(wù)發(fā)現(xiàn)已經(jīng)被廢棄,所以也不推薦使用該配置。
qualifier: 為Feign Client 新增注解@Qualifier
url: 請求地址的絕對URL,或者解析的主機名
decode404: 調(diào)用該feign client發(fā)生了常見的404錯誤時,是否調(diào)用decoder進行解碼異常信息返回,否則拋出FeignException。
fallback: 定義容錯的處理類,當(dāng)調(diào)用遠(yuǎn)程接口失敗或超時時,會調(diào)用對應(yīng)接口的容錯邏輯,fallback 指定的類必須實現(xiàn)@FeignClient標(biāo)記的接口。實現(xiàn)的法方法即對應(yīng)接口的容錯處理邏輯。
fallbackFactory: 工廠類,用于生成fallback 類示例,通過這個屬性我們可以實現(xiàn)每個接口通用的容錯邏輯,減少重復(fù)的代碼。
path: 定義當(dāng)前FeignClient的所有方法映射加統(tǒng)一前綴。
primary: 是否將此Feign代理標(biāo)記為一個Primary Bean,默認(rèn)為ture
Fegin的核心配置
Fegin的配置方式有兩種。
一種是Java 代碼配置,需要在主程序啟動入口用@EnableFeignClients(defaultConfiguration = DefaultFeignConfiguration.java)來引用配置。
第二種是直接配置文件配置,在application.yml或者application.properties中配置。
我們應(yīng)該知道的是,如果通過Java代碼的方式配置 Feign,然后有通過屬性文件的方式配置Feign,屬性文件中的Frign的配置會覆蓋Java代碼的配置。
但是可以配置 feign.client.default-to-properties=fasle來改變Feign配置生效的優(yōu)先級。
本文主要講解一些日常常用的配置,通過配置文件。
Spring Cloud Feign 支持請求和響應(yīng)進行GZIP壓縮來提高通信效率。
# 開啟GZIP壓縮配置 #請求GZIP壓縮 feign.compression.request.enable=true #響應(yīng)GIZP壓縮 feign.compression.response.enable=true #壓縮支持的mime type feign.compression.request.mime-types=text/xml,application/xml.application/json feign.compression.request.min-request-size=1024 #壓縮數(shù)據(jù)大小的最小值
Feign 為每一個FeignClient都提供了feign.logger實例,可在配置中或者java代碼中開啟日志。
NONE 表示不輸出日志。BASIC 表示只輸出請求方法的 URL 和響應(yīng)的狀態(tài)碼以及執(zhí)行的時間。HEADERS 將 BASIC 信息和請求頭信息輸出。FULL 會輸出全部完整的請求信息。
logging: level: com.javaer.study: debugfeign: client: config: # 要調(diào)用服務(wù)的名稱 java-master: loggerLevel: full
Fegin的超時配置
Ribbon 超時配置
當(dāng)系統(tǒng)出現(xiàn)Read time out,說明是 Ribbon 超時了,需要在配置文件中進行控制處理
### Ribbon 配置ribbon: # 連接超時 ConnectTimeout: 2000 # 響應(yīng)超時 ReadTimeout: 5000
Hystrix 超時配置
Fegin 高版本的 Hystrix 默認(rèn)是關(guān)閉的。需要以下配置開啟:
### Feign 配置feign: # 開啟斷路器(熔斷器) hystrix: enabled: true
為了避免超時,我們可以根據(jù)業(yè)務(wù)情況來配置自己的超時時間,此處配置熔斷時間為:5000/毫秒。
注意:建議 Ribbon 的超時時間不要大于 Hystrix 的超時時間
### Hystrix 配置hystrix: # 這樣將會自動配置一個 Hystrix 并發(fā)策略插件的 hook,這個 hook 會將 SecurityContext 從主線程傳輸?shù)?nbsp;Hystrix 的命令。 # 因為 Hystrix 不允許注冊多個 Hystrix 策略,所以可以聲明 HystrixConcurrencyStrategy # 為一個 Spring bean 來實現(xiàn)擴展。Spring Cloud 會在 Spring 的上下文中查找你的實現(xiàn),并將其包裝在自己的插件中。 shareSecurityContext: true command: default: circuitBreaker: # 當(dāng)在配置時間窗口內(nèi)達(dá)到此數(shù)量的失敗后,進行短路。默認(rèn)20個 requestVolumeThreshold: 1 # 觸發(fā)短路的時間值,當(dāng)該值設(shè)為5000時,則當(dāng)觸發(fā) circuit break 后的5000毫秒內(nèi)都會拒絕request # 也就是5000毫秒后才會關(guān)閉circuit。默認(rèn)5000 sleepWindowInMilliseconds: 15000 # 強制打開熔斷器,如果打開這個開關(guān),那么拒絕所有request,默認(rèn)false forceOpen: false # 強制關(guān)閉熔斷器 如果這個開關(guān)打開,circuit將一直關(guān)閉且忽略,默認(rèn)false forceClosed: false execution: isolation: thread: # 熔斷器超時時間,默認(rèn):1000/毫秒 timeoutInMilliseconds: 5000
Fegin的繼承特性
Spring Cloud Feign提供了繼承特性,所謂的繼承特性就是將一些公共操作提取到一個父接口中,從而繼承父接口中的操作,減少代碼的重復(fù)開發(fā),節(jié)約開發(fā)成本。
1、優(yōu)點
可以將接口的定義從 Controller 中剝離,同時配合 Maven 私有倉庫就可以輕易地實現(xiàn)接口定義的共享,不用再復(fù)制粘貼接口進行綁定,而是實現(xiàn)在構(gòu)建期的接口綁定,從而有效減少服務(wù)客戶端的綁定配置。
2、缺點
由于接口在構(gòu)建期間就建立起了依賴,那么接口變動就會對項目構(gòu)建造成影響,可能服務(wù)提供方修改了一個接口定義,那么會直接導(dǎo)致客戶端工程的構(gòu)建失敗。
所以,如果開發(fā)團隊通過此方法來實現(xiàn)接口共享的話,建議在開發(fā)評審期間嚴(yán)格遵守面向?qū)ο蟮拈_閉原則,盡可能地做好前后版本的兼容,防止?fàn)恳话l(fā)而動全身的后果,增加團隊不必要的維護工作量。
Fegin重試機制
在 Spring Cloud Feign 中默認(rèn)實現(xiàn)了請求的重試機制,下面配置作用是:當(dāng)訪問到故障請求的時候,它會再嘗試訪問一次當(dāng)前實例(次數(shù)由 MaxAutoRetries 配置),如果不行,就換一個實例進行訪問,如果還不行,再換一次實例訪問(更換次數(shù)由 MaxAutoRetriesNextServer 配置),如果依然不行,返回失敗信息。
注意:Ribbon 的超時與 Hystrix 的超時是兩個概念。為了讓上述實現(xiàn)有效,我們需要讓 Hystrix 的超時時間大于 Ribbon 的超時時間,否則 Hystrix 命令超時后,該命令直接熔斷,重試機制就沒有任何意義了。
#斷路器的超時時長需要大于Ribbon的超時時間,不然不會觸發(fā)重試hystrix.command.default.execution.isolation.thread.timeoutInMilliseconds=10000#請求連接超時時間fegin-service.ribbon.ConnectTimeout=500#請求處理的超時時間fegin-service.ribbon.ReadTimeout=1000#對所有請求都進行重試(是否所有操作都重試,若false則僅get請求重試)fegin-service.ribbon.OkToRetryOnAllOperations=true#對當(dāng)前實例的重試次數(shù)fegin-service.ribbon.MaxAutoRetries=1#切換實例的重試次數(shù)fegin-service.ribbon.MaxAutoRetriesNextServer=2
到此,相信大家對“如何深入學(xué)習(xí)SpringCloud Fegin”有了更深的了解,不妨來實際操作一番吧!這里是億速云網(wǎng)站,更多相關(guān)內(nèi)容可以進入相關(guān)頻道進行查詢,關(guān)注我們,繼續(xù)學(xué)習(xí)!
免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點不代表本網(wǎng)站立場,如果涉及侵權(quán)請聯(lián)系站長郵箱:is@yisu.com進行舉報,并提供相關(guān)證據(jù),一經(jīng)查實,將立刻刪除涉嫌侵權(quán)內(nèi)容。