feign上傳文件
① Feign Client超時時間配置以及單獨給某介面設置超時時間方法記錄
直奔主題,FeignClient面對服務級有三種超時時間配置:
feign配置是在ribbon配置的基礎上做了擴展,可以支持服務級超時時間配置,所以,feign配置和ribbon配置的效果應該是一樣的。
SpringCloud對這兩種配置的優先順序順序如下:
Feign局部配置 > Feign全局配置 > Ribbon局部配置 > Ribbon全局配置
在feign-core的jar包里有個Request類
在feign介面里加入這個參數就可以單獨為介面單獨設置超時時間了
調用的時候new 一下Options對象
這樣就可以為那些單獨需要很長時間才能完成的介面(比如大文件上傳等)設置超時時間了。
參考: https://www.cnblogs.com/east7/p/15858644.html
https://www.jianshu.com/p/d4d183f0be5b
② WebSocket SpringBoot實現文件上傳進度消息通知
文件上傳進度消息:
非同步耗時任務完成消息:
常見方案:
根據解析器構造,傳入必要參數。該解析器將替代默認實現
spring為WebSocket提供了很好的支持,參照官方文檔即可完成服務搭建
繼承 類,重寫 registerStompEndpoints() configureMessageBroker() configureClientInboundChannel() 方法。
此處通過註解切面,在需要執行的方法前後想Message服務發送消息
該切面將以@SendMessage註解為切入點,利用反射獲取形參名及參數值,封裝MessageDto,調用Feign介面向消息模塊發送消息
文件上傳監聽日誌,成功監聽上傳進度
文件上傳進度消息發送日誌
耗時任務消息模塊發送日誌
前端消息渲染效果
大功告成!
尚有諸多缺點,但保證了基礎功能夠用,諸位大佬可以做個小參考。
③ 上傳文件,以及通過 Feign 調用上傳文件介面
(1)工具類
(2)定義介面
(3)調用 http://localhost:8080/image/upload 進行測試。
在目標文件夾中會出現上傳的文件。
(1)定義一個 FeignClient 。
(2)調用上面定義的 FeignClient 介面。
(3)調用 http://localhost:8080/test 介面,控制台輸出如下:
說明一切正常。
④ Spring Cloud Feign使用詳解
通過前面兩章對Spring Cloud Ribbon和Spring Cloud Hystrix的介紹,我們已經掌握了開發微服務應用時,兩個重要武器,學會了如何在微服務架構中實現客戶端負載均衡的服務調用以及如何通過斷路器來保護我們的微服務應用。這兩者將被作為基礎工具類框架廣泛地應用在各個微服務的實現中,不僅包括我們自身的業務類微服務,也包括一些基礎設施類微服務(比如網關)。此外,在實踐過程中,我們會發現對這兩個框架的使用幾乎是同時出現的。既然如此,那麼是否有更高層次的封裝來整合這兩個基礎工具以簡化開發呢?本章我們即將介紹的Spring Cloud Ribbon與Spring Cloud Hystrix,除了提供這兩者的強大功能之外,它還提供了一種聲明式的Web服務客戶端定義方式。
我們在使用Spring Cloud Ribbon時,通常都會利用它對RestTemplate的請求攔截來實現對依賴服務的介面調用,而RestTemplate已經實現了對HTTP請求的封裝處理,形成了一套模版化的調用方法。在之前的例子中,我們只是簡單介紹了RestTemplate調用對實現,但是在實際開發中,由於對服務依賴對調用可能不止於一處,往往一個介面會被多處調用,所以我們通常都會針對各個微服務自行封裝一些客戶端累來包裝這些依賴服務的調用。這個時候我們會發現,由於RestTemplate的封裝,幾乎每一個調用都是簡單的模版化內容。綜合上述這些情況,Spring Cloud Fegin在此基礎上做了進一步封裝,由它來幫助我們定義和實現依賴服務介面的定義。在Spring Cloud Feign的實現下,我們只需創建一個介面並用註解的方式來配置它,即可完成對服務提供方的介面綁定,簡化了在使用Spring Cloud Ribbon時自行封裝服務調用客戶端的開發量。Spring Cloud Feign具備可插拔的註解支持,包括Feign註解和JAX-RS註解。同時,為了適應Spring的廣大用戶,它在Netflix Feign的基礎上擴展了對Spring MVC的註解支持。這對於習慣於Spring MVC的開發者來說,無疑是一個好消息,你我這樣可以大大減少學習適應它的成本。另外,對於Feign自身的一些主要組件,比如編碼器和解碼器等,它也以可插拔的方式提供,在有需求等時候我們以方便擴張和替換它們。
在本節中,我們將通過一個簡單示例來展示Spring Cloud Feign在服務客戶端定義所帶來的便利。下面等示例將繼續使用之前我們實現等hello-service服務,這里我們會通過Spring Cloud Feign提供的聲明式服務綁定功能來實現對該服務介面的調用。
▪️首先,創建一個Spring Boot基礎工程,取名為kyle-service-feign,並在pom.xml中引入spring-cloud-starter-eureka和spring-cloud-starter-feign依賴,具體內容如下所示。
▪️創建應用主類Application,並通過@EnableFeignClients註解開啟Spring Cloud Feign的支持功能。
▪️定義HelloServiceFeign,介面@FeignClient註解指定服務名來綁定服務,然後再使用Spring MVC的註解來綁定具體該服務提供的REST介面。
▪️接著,創建一個RestClientController來實現對Feign客戶端的調用。使用@Autowired直接注入上面定義的HelloServiceFeign實例,並在postPerson函數中調用這個綁定了hello-service服務介面的客戶端來向該服務發起/hello介面的調用。
▪️最後,同Ribbon實現的服務消費者一樣,需要在application.properties中指定服務注冊中心,並定義自身的服務名為feign-service-provider,為了方便本地調試與之前的Ribbon消費者區分,埠使用8868。
發送幾次GET請求到 http://localhost:8868/client/getHost?name=kyle ,可以得到如之前Ribbon實現時一樣到效果,正確返回 hi, kyle! i from 10.166.37.142:8877 。依然是利用Ribbon維護了針對HELLO-SERVICE-PROVIDER的服務列表信息,並且通過輪詢實現了客戶端負載均衡。而與Ribbon不同到是,通過Feign只需定義服務綁定介面,以聲明式的方法,優雅而簡單地實現了服務調用。
現實系統中的各種業務介面要比上一節復雜得多,我們會再HTTP的各個位置傳入各種不同類型的參數,並且再返回響應的時候也可能是一個復雜的對象結構。再本節中,我們將詳細介紹Feign中的不同形式參數的綁定方法。
再開始介紹Spring Cloud Feign的參數綁定之前,我們先擴張以下服務提供者hello-service-provider。增加下面這些介面,其中包含帶有Request參數的請求、帶有Header信息的請求、帶有RequestBody的請求以及請求響應體中是一個對象的請求。
在完成了對hello-service-provider的改造之後,下面我們開始在快速入門示例的kyle-service-feign應用中實現這些新增的綁定。
這里一定要注意,再定義各參數綁定時,@RequestParam、@RequestHeader等可以指定參數名稱的主角,它們的value千萬不能少。在Spring MVC程序中,這些註解會根據參數名來作為默認值,但是在Feign中綁定參數必須通過value屬性來指明具體的參數名,不然會拋出==IllegalStateException==異常,value屬性不能為空。
在完成上述改造之後,啟動服務注冊中心、兩個hello-service-privider服務以及我們改造的kyle-service-feign。通過發送GET請求到== http://localhost:8868/feign/head/getHost?name=kyle&age=18== ,通過發送POST請求到== http://localhost:8868/feign/project/postPerson== ,請求觸發HelloServiceFeign對新增介面的調用。最終,我們會獲得如下圖的結果,代表介面綁定和調試成功。
由於Spring Cloud Feign的客戶端負載均衡是通過Spring Cloud Ribbon實現的,所以我們可以直接配置Ribbon客戶端的方式來自定義各個服務客戶端調用參數。那麼我們如何使用Spring Cloud Feign的工程中使用Ribbon的配置呢?
全局配置的方法非常簡單,我們可以直接使用ribbon.<key>=<value>的方式來設置ribbon的各項默認參數。如下:
大多數情況下,我們對於服務調用的超時時間可能會根據實際服務的特性做一些調整,所以僅僅進行個性化配置的方式與使用Spring Cloud Ribbon時的配置方式是意義的,都採用<client>.ribbon.key=value的格式進行設置。但是,這里就有一個疑問了,<cleint>所指代的Ribbon客戶端在那裡呢?
回想一下,在定義Feign客戶端的時候,我們使用了@FeignClient註解。在初始化過程中,Spring Cloud Feign會根據該註解的name屬性或value屬性指定的服務名,自動創建一個同名的Ribbon客戶端。如下:
Spring Cloud Ribbon默認負載均衡策略是輪詢策略,不過該不一定滿足我們的需要。Ribbon一共提供了7種負載均衡策略,如果我們需要ZoneAvoidanceRule,首先要在application.properties文件中添加配置,如下所示:
不過,只是添加了如上配置,還無法實現負載均衡策略的更改。我們還需要實例化該策略,可以在應用主類中直接加入IRule實例的創建,如下:
想要深入了解Ribbon的原理,或者想詳細了解7種負載均衡策略的,可以參考我另一篇博客 《Ribbon詳解》 ,我會在博客最下面給出鏈接。
從前兩節來看在Spring Boot工程中使用Feign,非常的便利。不過實際生產中,在微服務的初期只能從次要系統開始進行改造,可能很多系統由於歷史原因仍然是非Spring Boot的工程,然後這些系統如何使用微服務?如何使用注冊中心?如何進行負載均衡呢?
▪️首先我們在kyle-service-feign創建調用介面OldSystemPostFeign和OldSystemGetFeign,然後使用feign註解提供的相關註解,包含@RequestLine、@Param、@HeaderParam、@Headers等,主要提供了請求方法、請求參數、頭信息參數等操作。
▪️我們需要脫離Spring Boot和Spring Cloud的支持,使用feign原生的一些東西。在進行Feign封裝之前我們需要一些額外的組件,比如編碼器。新增組件依賴如下所示:
▪️我們需要一個feign-clientproperties文件,來進行ribbon相關的參數配置,配置如下:
▪️到目前為止,相關要素已經准備好了,接下來需要feign和ribbon的封裝了。我們需要創建類,作用是載入feign-client.properties文件,並創建一個附帶負載均衡器的RibbonClient,然後封裝出一個附帶Jackson編解碼器的FeignClient,如下所示:
▪️然後我需要一個測試類FeignClientTest,測試以上3個介面,然後將結果輸出到控台如下所示:
▪️在完成上述改造之後,啟動測試類FeignClientTest,獲得如下的結果,說明調用使用了負載均衡。
細心的同學會發現,非Spring Boot使用feign調用根本沒有使用到注冊中心的服務發現。在此我提供一個思路,我們可以調用代理微服務,再由代理進行服務發現。那麼這個代理服務應該具備哪些功能和作用呢?我將會在下一篇博客詳細講述Netflix公司的API網關組件zuul,它承擔路由轉發,攔截過濾,流量控制等功能。
▪️ 第一次請求失敗
原因:由於spring的懶載入機制導致大量的類只有在真正使用的才會真正創建,由於默認的熔斷超時時間(1秒)過短,導致第一次請求很容易失敗,特別互相依賴復雜的時候。
解決方法:提升熔斷超時時間和ribbon超時時間,配置如下:
▪️ Feign的Http Client
Feign在默認情況下使用的是JDK原生URLConnection發送HTTP請求,沒有連接池,但是對每個地址會保持一個長連接,即利用HTTP的persistence connection。我們可以用Apache的HTTP Client替換Feign原始的http client,從而獲取連接池、超時時間等與性能息息相關的控制能力。Spring Cloud從Brixtion.SR5版本開始支持這種替換,首先在項目中聲明Apcahe HTTP Client和feign-httpclient依賴,然後在application.properties中添加:
▪️ 如何實現在feign請求之前進行操作
feign組件提供了請求操作介面RequestInterceptor,實現之後對apply函數進行重寫就能對request進行修改,包括header和body操作。
▪️ 請求壓縮
Spring Cloud Feign支持對請求和響應進行GZIP壓縮,以減少通信過程中的性能損耗。我們只需通過下面兩個參數設置,就能開啟請求與響應的壓縮功能:
同時,我們還能對請求壓縮做一些更細致的設置,比如下面的配置內容指定了壓縮的請求數據類型,並設置了壓縮的大小下限,只有超過這個大小的請求才會對其進行壓縮。
上述配置的feign.compression.request.nime-types和feign.compression.requestmin-request-size均為默認值。
▪️ 日誌配置
Spring Cloud Feign在構建被@FeignClient註解修飾的服務客戶端時,會為每一個客戶端都創建一個feign的請求細節。可以在 application.properties 文件中使用logging.level.<FeignClient>的參數配置格式來開啟指定Feign客戶端的DEBUG日誌,其中<FeignClient>為Feign客戶端定義捷克隊完整路徑,比如針對本博文中我們實現的HelloServiceFeign可以如下配置開啟:
但是,只是添加了如上配置,還無法實現對DEBUG日誌的輸出。這時由於Feign客戶端默認對Logger.Level對象定義為NONE級別,該界別不會記錄任何Feign調用過程中對信息,所以我們需要調整它對級別,針對全局對日誌級別,可以在應用主類中直接假如Logger.Level的Bean創建,具體如下:
在調整日誌級別為FULL之後,我們可以再訪問第一節的 http://localhost:8868/feign/postPerson?name=kyle 介面,這是我們在kyle-service-feign的控制台中可以看到類似下面的請求詳細的日誌:
對於Feign的Logger級別主要有下面4類,可根據實際需要進行調整使用。
▪️ 負載均衡異常
當我們只是對一個微服務進行調用的時候,Ribbon提供的支持好像沒什麼問題。不過在我們進行多個微服務調用時會產生異常,這也是大多數人忽略的。
情景描述 :2個應用B和C,在A中使用feign client調用B和C;測試結果,假如先調用B,再調用C都是有效的,但是再調用B就是無效的;(B,C先後順序改變,都會產生這個bug)
解決方法 :在主啟動類使用註解@RibbonClient,進行RibbonClient配置,如下所示:
看不懂是嗎?不要緊,我下面詳細講解一下,先看一下我們之前的非Spring Boot工程中封裝FeignClient:
OldSystemPostFeign只是一個介面,Feign為什麼需要使用介面來調用遠程介面?原因就是使用JDK動態代理,我們可以去看Feign是如何進行處理。
