日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

05 | REST消息通信:如何使用 OpenFeign 简化服务间通信

發布時間:2024/10/6 编程问答 37 豆豆
生活随笔 收集整理的這篇文章主要介紹了 05 | REST消息通信:如何使用 OpenFeign 简化服务间通信 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

上一講我們學習了 Ribbon 與 RestTemplate 兩個組件。Ribbon 提供了客戶端負載均衡,而 RestTemplate 則封裝了 HTTP 的通訊,簡化了發送請求的過程。兩者相輔相成構建了服務間的高可用通信。

不過在使用后,你也應該會發現 RestTemplate,它只是對 HTTP 的簡單封裝,像 URL、請求參數、請求頭、請求體這些細節都需要我們自己處理,如此底層的操作都暴露出來這肯定不利于項目團隊間協作,因此就需要一種封裝度更高、使用更簡單的技術屏蔽通信底層復雜度。好在 Spring Cloud 團隊提供了 OpenFeign 技術,大幅簡化了服務間高可用通信處理過程。本講將主要介紹三部分:

  • 介紹 Feign 與 OpenFeign;
  • 講解 OpenFeign 的使用辦法;
  • 講解生產環境 OpenFeign 的配置優化。

Feign 與 OpenFeign

Spring Cloud OpenFeign 并不是獨立的技術。它底層基于 Netflix Feign,Netflix Feign 是 Netflix 設計的開源的聲明式 WebService 客戶端,用于簡化服務間通信。Netflix Feign 采用“接口+注解”的方式開發,通過模仿 RPC 的客戶端與服務器模式(CS),采用接口方式開發來屏蔽網絡通信的細節。OpenFeign 則是在 Netflix Feign 的基礎上進行封裝,結合原有 Spring MVC 的注解,對 Spring Cloud 微服務通信提供了良好的支持。使用 OpenFeign 開發的方式與開發 Spring MVC Controller 頗為相似。下面我們通過代碼說明 OpenFeign 的各種開發技巧。

OpenFeign 的使用辦法

為了便于理解,我們模擬實際案例進行說明。假設某電商平臺日常訂單業務中,為保證每一筆訂單不會超賣,在創建訂單前訂單服務(order-service)首先去倉儲服務(warehouse-service)檢查對應商品 skuId(品類編號)的庫存數量是否足夠,庫存充足創建訂單,不存不足 App 前端提示“庫存不足”。

在這個業務中,訂單服務依賴于倉儲服務,那倉儲服務就是服務提供者,訂單服務是服務消費者。下面我們通過代碼還原這個場景。

首先,先創建倉儲服務(warehouse-service),倉儲服務作為提供者就是標準微服務,使用 Spring Boot 開發。

第一步,利用 Spring Initializr 向導創建 warehouse-service 工程。確保在 pom.xml 引入以下依賴。

<dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifactId></dependency><dependency><groupId>com.alibaba.cloud</groupId><artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId></dependency>

第二步,編輯 application.yml 新增 Nacos 通信配置。

spring:application:name: warehouse-service #應用/微服務名字cloud:nacos:discovery:server-addr: 192.168.31.102:8848 #nacos服務器地址username: nacos #用戶名密碼password: nacosserver:port: 80

第三步,創建 Stock 庫存類,用于保存庫存數據。

package com.lagou.warehouseservice.dto;//庫存商品對象public class Stock {private Long skuId; //商品品類編號private String title; //商品與品類名稱private Integer quantity; //庫存數量private String unit; //單位private String description; //描述信息//帶參構造函數public Stock(Long skuId, String title, Integer quantity, String unit) {this.skuId = skuId;this.title = title;this.quantity = quantity;this.unit = unit;}//getter and setter省略...}

第四步,創建倉儲服務控制器 WarehouseController,通過 getStock() 方法傳入 skuId 編號則返回具體商品庫存數量,代碼中模擬 skuId 編號為 1101 的“紫色 128G iPhone 11”庫存 32 臺,而編號 1102 的“白色 256G iPhone 11”已沒有庫存。

package com.lagou.warehouseservice.controller;//省略 import 部分//倉儲服務控制器@RestControllerpublic class WarehouseController {/*** 查詢對應 skuId 的庫存狀況* @param skuId skuId* @return Stock 庫存對象*/@GetMapping("/stock")public Stock getStock(Long skuId){Map result = new HashMap();Stock stock = null;if(skuId == 1101l){//模擬有庫存商品stock = new Stock(1101l, "Apple iPhone 11 128GB 紫色", 32, "臺");stock.setDescription("Apple 11 紫色版對應商品描述");}else if(skuId == 1102l){//模擬無庫存商品stock = new Stock(1101l, "Apple iPhone 11 256GB 白色", 0, "臺");stock.setDescription("Apple 11 白色版對應商品描述");}else{//演示案例,暫不考慮無對應 skuId 的情況}return stock;}}

可以看到 WarehouseController 就是普通的 Spring MVC 控制器,對外暴露了 stock 接口,當應用啟動后,查看 Nacos 服務列表,已出現 warehouse-service 實例。

訪問下面的 URL 可看到 Stock 對象 JSON 序列化數據。

http://192.168.31.111/stock?skuId=1101{skuId: 1101,title: "Apple iPhone 11 128GB 紫色",quantity : 32,unit: "臺",description:"Apple 11 紫色版對應商品描述"}

至此,服務提供者 warehouse-service 示例代碼已開發完畢。下面我們要開發服務消費者 order-service。

第一步,確保利用 Spring Initializr 創建 order-service 工程,確保 pom.xml 引入以下 3 個依賴。

<dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifactId></dependency><dependency><groupId>com.alibaba.cloud</groupId><artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId></dependency><dependency><groupId>org.springframework.cloud</groupId><artifactId>spring-cloud-starter-openfeign</artifactId><version>2.2.5.RELEASE</version></dependency>

這里關鍵在于服務消費者依賴了 spring-cloud-starter-openfeign,在 Spring Boot 工程會自動引入 Spring Cloud OpenFeign 與 Netflix Feign 的 Jar 包。這里有個重要細節,當我們引入 OpenFeign 的時候,在 Maven 依賴中會出現 netflix-ribbon 負載均衡器的身影。

沒錯,OpenFeign 為了保證通信高可用,底層也是采用 Ribbon 實現負載均衡,其原理與 Ribbon+RestTemplate 完全相同,只不過相較 RestTemplate,OpenFeign 封裝度更高罷了。

第二步,啟用 OpenFeign 需要在應用入口 OrderServiceApplication 增加 @EnableFeignClients 注解,其含義為通知 Spring 啟用 OpenFeign 聲明式通信。

package com.lagou.orderservice;import org.springframework.boot.SpringApplication;import org.springframework.boot.autoconfigure.SpringBootApplication;import org.springframework.cloud.openfeign.EnableFeignClients;@SpringBootApplication@EnableFeignClients //啟用OpenFeignpublic class OrderServiceApplication {public static void main(String[] args) {SpringApplication.run(OrderServiceApplication.class, args);}}

第三步,默認 OpenFeign 并不需要任何配置,在 application.yml 配置好 Nacos 通信即可。

spring:application:name: order-servicecloud:nacos:discovery:server-addr: 192.168.31.102:8848username: nacospassword: nacosserver:port: 80

第四步,最重要的地方來了,創建OpenFeign的通信接口與響應對象,這里先給出完整代碼。

package com.lagou.orderservice.feignclient;import com.lagou.orderservice.dto.Stock;import org.springframework.cloud.openfeign.FeignClient;import org.springframework.web.bind.annotation.GetMapping;import org.springframework.web.bind.annotation.RequestParam;@FeignClient("warehouse-service")public interface WarehouseServiceFeignClient {@GetMapping("/stock")public Stock getStock(@RequestParam("skuId") Long skuId);}

在 order-service 工程下,創建一個 feignclient 包用于保存通信接口。OpenFeign 通過“接口+注解”形式描述數據傳輸邏輯,并不需要程序員編寫具體實現代碼便能實現服務間高可用通信,下面我們來學習這段代碼:

  • @FeignClient 注解說明當前接口為 OpenFeign 通信客戶端,參數值 warehouse-service 為服務提供者 ID,這一項必須與 Nacos 注冊 ID 保持一致。在 OpenFeign 發送請求前會自動在 Nacos 查詢 warehouse-service 所有可用實例信息,再通過內置的 Ribbon 負載均衡選擇一個實例發起 RESTful 請求,進而保證通信高可用。
  • 聲明的方法結構,接口中定義的方法通常與服務提供者的方法定義保持一致。這里有個非常重要的細節:用于接收數據的 Stock 對象并不強制要求與提供者端 Stock 對象完全相同,消費者端的 Stock 類可以根據業務需要刪減屬性,但屬性必須要與提供者響應的 JSON 屬性保持一致。距離說明,我們在代碼發現消費者端 Stock 的包名與代碼與提供者都不盡相同,而且因為消費者不需要 description 屬性便將其刪除,其余屬性只要保證與服務提供者響應 JSON 保持一致,在 OpenFeign 獲取響應后便根據 JSON 屬性名自動反序列化到 Stock 對象中。
#服務提供者返回的響應{skuId: 1101,title: "Apple iPhone 11 128GB 紫色",quantity: 32,unit: "臺",description: "Apple 11 紫色版對應商品描述"} package com.lagou.orderservice.dto;//消費者端接收響應Stock對象public class Stock {private Long skuId; //商品品類編號private String title; //商品與品類名稱private Integer quantity; //庫存數量private String unit; //單位@Overridepublic String toString() {return "Stock{" +"skuId=" + skuId +", title='" + title + '\'' +", quantity=" + quantity +", unit='" + unit + '\'' +'}';}//getter與setter省略}
  • @GetMapping/@PostMapping,以前我們在編寫 Spring MVC 控制器時經常使用 @GetMapping 或者@ PostMapping 聲明映射方法的請求類型。雖然 OpenFeign 也使用了這些注解,但含義完全不同。在消費者端這些注解的含義是:OpenFeign 向服務提供者 warehouse-service 的 stock 接口發起 Get 請求。簡單總結下,如果在服務提供者書寫 @GetMapping 是說明 Controller 接收數據的請求類型必須是 Get,而寫在消費者端接口中則說明 OpenFeign 采用 Get 請求發送數據,大多數情況下消費者發送的請求類型、URI 與提供者定義要保持一致。
  • @RequestParam,該注解說明方法參數與請求參數之間的映射關系。舉例說明,當調用接口的 getStock() 方法時 skuId 參數值為 1101,那實際通信時 OpenFeign 發送的 Get 請求格式就是:
http://warehouse-service可用實例 ip:端口/stock?skuId=1101

介紹每一個細節后,我用自然語言完整描述處理邏輯:

  • 在第一次訪問 WarehouseServiceFeignClient 接口時,Spring 自動生成接口的實現類并實例化對象。
  • 當調用 getStock() 方法時,Ribbon 獲取 warehouse-service 可用實例信息,根據負載均衡策略選擇合適實例。
  • OpenFeign 根據方法上注解描述的映射關系生成完整的 URL 并發送 HTTP 請求,如果請求方法是 @PostMapping,則參數會附加在請求體中進行發送。
  • http://warehouse-service 可用實例 ip:端口/stock?skuId=xxx

    4.warehouse-service 處理完畢返回 JSON 數據,消費者端 OpenFeign 接收 JSON 的同時反序列化到 Stock 對象,并將該對象返回。
    到這里我們花了較大的篇幅介紹 OpenFeign 的執行過程,那該怎么使用呢?這就是第五步的事情了。

    第五步,在消費者 Controller 中對 FeignClient 接口進行注入,像調用本地方法一樣完成業務邏輯。

    package com.lagou.orderservice.controller;import com.lagou.orderservice.dto.Stock;import com.lagou.orderservice.feignclient.WarehouseServiceFeignClient;import org.springframework.web.bind.annotation.GetMapping;import org.springframework.web.bind.annotation.RestController;import javax.annotation.Resource;import java.util.LinkedHashMap;import java.util.Map;@RestControllerpublic class OrderController {//利用@Resource將IOC容器中自動實例化的實現類對象進行注入@Resourceprivate WarehouseServiceFeignClient warehouseServiceFeignClient;/*** 創建訂單業務邏輯* @param skuId 商品類別編號* @param salesQuantity 銷售數量* @return*/@GetMapping("/create_order")public Map createOrder(Long skuId , Long salesQuantity){Map result = new LinkedHashMap();//查詢商品庫存,像調用本地方法一樣完成業務邏輯。Stock stock = warehouseServiceFeignClient.getStock(skuId);System.out.println(stock);if(salesQuantity <= stock.getQuantity()){//創建訂單相關代碼,此處省略//CODE=SUCCESS代表訂單創建成功result.put("code" , "SUCCESS");result.put("skuId", skuId);result.put("message", "訂單創建成功");}else{//code=NOT_ENOUGN_STOCK代表庫存不足result.put("code", "NOT_ENOUGH_STOCK");result.put("skuId", skuId);result.put("message", "商品庫存數量不足");}return result;}}

    啟動后分別傳入不同 skuId 與銷售數量??梢钥吹?1101 商品庫存充足訂單創建成功,1102 商品因為沒有庫存導致無法創建訂單。

    http://192.168.1.120/create_order?skuId=1101&salesQuantity=1{code: "SUCCESS", skuId: 1101, message: "訂單創建成功" }

    創建訂單成功消息

    http://192.168.1.120/create_order?skuId=1102&salesQuantity=1{code: "NOT_ENOUGH_STOCK", skuId: 1102, message: "商品庫存數量不足" }

    庫存數量不足錯誤提示

    到這里已經基于 OpenFeign 實現了服務間通信。但事情還不算完,OpenFeign 默認的配置并不能滿足生產環境的要求,下面咱們來講解在生產環境下 OpenFeign 還需要哪些必要的優化配置。

    生產環境 OpenFeign 的配置事項

    如何更改 OpenFeign 默認的負載均衡策略
    前面提到,在 OpenFeign 使用時默認引用 Ribbon 實現客戶端負載均衡。那如何設置 Ribbon 默認的負載均衡策略呢?在 OpenFeign 環境下,配置方式其實與之前 Ribbon+RestTemplate 方案完全相同,只需在 application.yml 中調整微服務通信時使用的負載均衡類即可。

    warehouse-service: #服務提供者的微服務IDribbon:#設置對應的負載均衡類NFLoadBalancerRuleClassName: com.netflix.loadbalancer.RandomRule

    開啟默認的 OpenFeign 數據壓縮功能
    在 OpenFeign 中,默認并沒有開啟數據壓縮功能。但如果你在服務間單次傳遞數據超過 1K 字節,強烈推薦開啟數據壓縮功能。默認 OpenFeign 使用 Gzip 方式壓縮數據,對于大文本通常壓縮后尺寸只相當于原始數據的 10%~30%,這會極大提高帶寬利用率。但有一種情況除外,如果應用屬于計算密集型,CPU 負載長期超過 70%,因數據壓縮、解壓縮都需要 CPU 運算,開啟數據壓縮功能反而會給 CPU 增加額外負擔,導致系統性能降低,這是不可取的。

    feign:compression:request:# 開啟請求數據的壓縮功能enabled: true# 壓縮支持的MIME類型mime-types: text/xml,application/xml, application/json# 數據壓縮下限 1024表示傳輸數據大于1024 才會進行數據壓縮(最小壓縮值標準)min-request-size: 1024# 開啟響應數據的壓縮功能response:enabled: true

    替換默認通信組件

    OpenFeign 默認使用 Java 自帶的 URLConnection 對象創建 HTTP 請求,但接入生產時,如果能將底層通信組件更換為 Apache HttpClient、OKHttp 這樣的專用通信組件,基于這些組件自帶的連接池,可以更好地對 HTTP 連接對象進行重用與管理。作為 OpenFeign 目前默認支持 Apache HttpClient 與 OKHttp 兩款產品。我以OKHttp配置方式為例,為你展現配置方法。

  • 引入 feign-okhttp 依賴包。
  • <dependency><groupId>io.github.openfeign</groupId><artifactId>feign-okhttp</artifactId><version>11.0</version></dependency>
  • 在應用入口,利用 Java Config 形式初始化 OkHttpClient 對象。
  • @SpringBootApplication@EnableFeignClientspublic class OrderServiceApplication {//Spring IOC容器初始化時構建okHttpClient對象@Beanpublic okhttp3.OkHttpClient okHttpClient(){return new okhttp3.OkHttpClient.Builder()//讀取超時時間.readTimeout(10, TimeUnit.SECONDS)//連接超時時間.connectTimeout(10, TimeUnit.SECONDS)//寫超時時間.writeTimeout(10, TimeUnit.SECONDS)//設置連接池.connectionPool(new ConnectionPool()).build();}public static void main(String[] args) {SpringApplication.run(OrderServiceApplication.class, args);}}
  • 在 application.yml 中啟用 OkHttp。
  • feign:okhttp:enabled: true

    做到這里,我們已將OpenFeign的默認通信對象從URLConnection調整為OKHttp,至于替換為HttpClient組件的配置思路是基本相同的。如果需要了解OpenFeign更詳細的配置選項,可以訪問Spring Cloud OpenFeign的官方文檔進行學習。
    https://docs.spring.io/spring-cloud-openfeign/docs/2.2.6.RELEASE/reference/html/

    總結

    以上是生活随笔為你收集整理的05 | REST消息通信:如何使用 OpenFeign 简化服务间通信的全部內容,希望文章能夠幫你解決所遇到的問題。

    如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。