Ⅰ SpringCloud系列——Feign 服務調用
前面我們已經實現了服務的注冊與發現(請戳:SpringCloud系列——Eureka 服務注冊與發現),並且在注冊中心注冊了一個服務myspringboot,本文記錄多個服務之間使用Feign調用。
GitHub地址:https://github.com/OpenFeign/feign
官方文檔:https://cloud.spring.io/spring-cloud-static/spring-cloud-openfeign/2.1.0.RC2/single/spring-cloud-openfeign.html
提供者除了要在注冊中心注冊之外,不需要引入其他東西,注意以下幾點即可:
1、經測試,默認情況下,feign只能通過@RequestBody傳對象參數
2、接參只能出現一個復雜對象,例:public Result<list > list(@RequestBody UserVo entityVo) { ... }</list
3、提供者如果又要向其他消費者提供服務,又要向瀏覽器提供服務,建議保持原先的Controller,新建一個專門給消費者的Controller
測試Controller介面
消費者maven引入jar
配置文件
對日期的解析,消費者要跟提供者一致,不然會報json解析錯誤
服務調用
1、springdatejpa 應用名稱,是服務提供者在eureka注冊的名字,Feign會從注冊中心獲取實例
2、如果不想啟動eureka服務,直連本地開發:@FeignClient(name = "springdatejpa", path = "/user/",url = "http://localhost:10086"),或者無eureka,調用第三方服務,關閉eureka客戶端(eureka.client.enabled=false),url直接指定第三方服務地址,path指定路徑,介面的方法指定介面
3、如果使用@RequestMapping,最好指定調用方式
4、消費者的返回值必須與提供者的返回值一致,參數對象也要一致
5、2019-05-21補充:如需進行容錯處理(服務提供者發生異常),則需要配置fallback,如果需要獲取到報錯信息,則要配置fallbackFactory ,例:
Feign介面
更多@FeignClient註解參數配置,請參閱官方文檔
Controller層
啟動類
啟動類加入註解:@EnableFeignClients
成功注冊兩個服務
成功調用
1、啟動時報了個SQL錯誤
解決:配置文件連接數據時指定serverTimezone=GMT%2B8
2、當我將之前搭好的一個springboot-springdata-jpa整合項目在eureka注冊時出現了一個報錯
然後在網上查了下說是因為springboot版本問題(請戳:http://www.cnblogs.com/hbbbs/articles/8444013.html),之前這個項目用的是2.0.1.RELEASE,現在要在eureka注冊,pom引入了就出現了上面的報錯
解決:升級了springboot版本,2.1.0,項目正常啟動
2019-10-17補充 :Feign設置header請求頭
方法1,mapping的headers屬性,單一設置
方法2,自定義FeignInterceptor,全局設置
這樣就可以設置cookie,傳遞token等自定義值
常見場景1
通常我們一個服務web層、svc層、層,但有時候也會將拆分成兩個服務:
web服務提供靜態資源、頁面以及controller控制器控制跳轉,數據通過java調用svc服務獲取;
svc服務,進行操作資料庫以及業務邏輯處理,同時提供介面給web服務調用;
特殊情況下我們想svc服務的介面也做登錄校驗,所有介面(除了登錄請求介面)都有做登錄校驗判斷,未登錄的無權訪問,這時候就需要做sessionId傳遞,將web服務的sessionId通過Feign調用時傳遞到svc服務
web服務
註:登錄成功後用sessionId作為key,登錄用戶的id作為value,保存到redis緩存中
登錄攔截器
自定義FeignInterceptor
svc服務
會話期的sessionId,關閉瀏覽器後就失效了,所以就會退出瀏覽器後就需要重新登陸,有些情況我們並不想這樣,我們想實現七天免登陸,這時候就需要自定義token,並且存放在cookie
登陸攔截器
登陸成功,設置cookie
推出登陸,銷毀cookie
代碼已經開源、託管到我的GitHub、碼雲:
GitHub:https://github.com/huanzi-qch/springCloud
碼雲:https://gitee.com/huanzi-qch/springCloud
作者:huanzi-qch
出處:https://www.cnblogs.com/huanzi-qch
Ⅱ 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是如何進行處理。
Ⅲ bbo和feign傳輸上下文信息
在兩個進程傳輸的過程中,例如A進程向B進程傳輸數據,一般都需要傳一些固定欄位信息,這些信息一般是與業務無關,像調用鏈追蹤,api網關等都需要傳輸此上下文信息。我們現在有兩個應用,應用A是訂單系統,應用B是用戶中台系統,而且我們是toB的業務,用戶是屬於某個企業的,該企業的唯一標識為corpId,每個應用對應一個唯一的應用id,還有多個應用的調用鏈追蹤需要傳輸traceId等,所以A調用B必須傳輸此幾個欄位,以下介紹bbo和feign傳輸上下文的方法。
Dubbo(讀音[ˈdʌbəʊ])是阿里巴巴公司開源的一個高性能優秀的服務框架使得應用可通過高性能的 RPC 實現服務的輸出和輸入功能,可以和 Spring框架無縫集成。Dubbo是一款高性能、輕量級的開源Java RPC框架,它提供了三大核心能力:面向介面的遠程方法調用,智能容錯和負載均衡,以及服務自動注冊和發現,具體想研究bbo可以參考bbo文檔,本文只介紹bbo傳輸上下文的方法:
註:採用http協議傳輸上下文信息,會將上下文欄位設置到header,但是頭信息中不能含有中文,所以需要進行編碼後傳輸,然後在接受端解碼。
Ⅳ 上傳文件,以及通過 Feign 調用上傳文件介面
(1)工具類
(2)定義介面
(3)調用 http://localhost:8080/image/upload 進行測試。
在目標文件夾中會出現上傳的文件。
(1)定義一個 FeignClient 。
(2)調用上面定義的 FeignClient 介面。
(3)調用 http://localhost:8080/test 介面,控制台輸出如下:
說明一切正常。
Ⅳ feign實現微服務間文件傳輸
項目開發過程中,由於業務需求,需要通過feign實現微服務間文件傳輸,但其報錯 Error converting request body,通過以下方式進行解決:
出現問題第一時間看是什麼問題,再根據問題去定位到官方網站去查詢,要會正確的搜索是很重要的。
Ⅵ feign介面調用時問題整理
我們平常在寫介面時,方法的入參中可能會有Date類型的參數,當抽成feign介面時,此時的Date類型的入參就會報錯。
解決方案:建議將事件類型的入參改為String,到具體微服務層面時再轉為Date類型即可。
介面的方法入參中,存在多個參數時,需要加上註解
解決方案:在feign介面中必須拆開。
項目中可能由於某些原因,前端頁面不能直接調用文件伺服器,所以需要通過後端的API層,調用feign介面,最終轉到文件伺服器上,但是feign介面本身是不支持文件傳遞的。
解決方案:
(1)增加maven依賴
(2)增加配置文件
我們項目在調用介面時,往往都會有帶請求頭的需求,但是通過feign介面後,請求頭會消失,因為feign原本是不支持請求頭的。
解決方案:增加請求頭相關的配置