SpringCloud 運用(2)—— 跨服務調度

上一篇:SpringCloud 入門(1)—— nacos 注冊中心-CSDN博客


1.RestTemplate 跨服務請求

RestTemplate 是 Spring 框架中的一個同步客戶端,用于與 HTTP 服務進行交互。它簡化了與 HTTP 服務器通信的過程,并且提供了對多種 HTTP 方法(如 GET、POST、PUT、DELETE 等)的支持,用于發送跨服務請求。

  <!--負載均衡器--><dependency><groupId>org.springframework.cloud</groupId><artifactId>spring-cloud-starter-loadbalancer</artifactId></dependency>

?1.1 配置Bean

在 Spring Boot 2.0 及以上版本中,RestTemplate 不再自動配置,因此需要自己創建 RestTemplate Bean

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.client.RestTemplate;@Configuration
public class RemoteCallConfig {@Bean@LoadBalancedpublic RestTemplate restTemplate() {return new RestTemplate();}
}

?1.2 構造函數注入RestTemplate

spring不推薦使用@AutoWired注解,進行自動注入。我們可以自己書寫構造函數注入

public class CartServiceImpl extends ServiceImpl<CartMapper, Cart> implements ICartService {private  RestTemplate restTemplate;public CartServiceImpl(RestTemplate restTemplate) {this.restTemplate = restTemplate;}
}

?也可以通過lombok注解,自動生成構造函數,進行注入

?@AllArgsConstructor全參構造注解,但使用該注解可能導致一些不需要通過構造傳參的變量,也會生成構造函數

@RequiredArgsConstructor注解,只有通過final修飾值,才會生成構造函數。?因為通過final修飾后,必需在定義時進行賦初始值,或者通過構造函數初始化

@RequiredArgsConstructor
public class CartServiceImpl extends ServiceImpl<CartMapper, Cart> implements ICartService {private final RestTemplate restTemplate;
}

1.3 RestTemplate的使用

ResponseEntity<List<ItemDTO>> response = restTemplate.exchange("http://localhost:8081/items?ids={ids}",//請求路徑HttpMethod.GET,//請求方式null,//請求實體new ParameterizedTypeReference<List<ItemDTO>>() { },//返回值類型List<ItemDTO>Map.of("ids", CollUtil.join(itemIds, ","))//請求參數, 
);
//CollUtil.join(itemIds, ",")將集合轉換成字符串,用逗號分隔。即集合123轉化為字符串1,2,3。
???????//Map.of() "ids"是鍵,字符串1,2,3是值

?我們可以看到http://localhost:8081/items中存在硬編碼,這里我們可以使用上一篇學習到的nacos服務注冊中心,將該微服務注冊到nacos中,然后通過服務名發送請求。

當你通過 RestTemplate 發起請求時,Spring Cloud 提供了客戶端負載均衡機制來決定具體發送到哪臺計算機。默認的負載均衡策略是輪詢(Round Robin)

這樣如果該微服務在多臺計算機都進行部署,并在nacos注冊后,就可以實現負載均衡了

nacos注冊中心地址教程:SpringCloud 入門(1)—— nacos 注冊中心-CSDN博客

注冊中心搭建完成后,使用構造函數將注入

@RequiredArgsConstructor
public class CartServiceImpl extends ServiceImpl<CartMapper, Cart> implements ICartService {private final RestTemplate restTemplate;private  final DiscoveryClient discoveryClient;//注冊中心
}

?默認情況下,采用輪詢的方式進行負載均衡

// 發起請求時,直接使用服務名稱
ResponseEntity<List<ItemDTO>> response = restTemplate.exchange("http://item-service/items?ids={ids}", // 使用服務名稱而不是具體實例 URIHttpMethod.GET,null,new ParameterizedTypeReference<List<ItemDTO>>() {},Map.of("ids", CollUtil.join(itemIds, ","))
);

?指定服務實例方式為隨機

 // 查找 item-service 服務的實例列表List<ServiceInstance> instances = discoveryClient.getInstances("item-service");if (instances.isEmpty()) {throw new RuntimeException("No instances available for item-service");}// 隨機選擇一個服務實例Random random = new Random();ServiceInstance instance = instances.get(random.nextInt(instances.size()));// 發起請求,查詢商品ResponseEntity<List<ItemDTO>> response = restTemplate.exchange(instance.getUri() + "/items?ids={ids}",HttpMethod.GET,null,new ParameterizedTypeReference<List<ItemDTO>>() {},Map.of("ids", CollUtil.join(itemIds, ",")));

利用Nacos實現了服務的治理,利用RestTemplate實現了服務的遠程調用。但是遠程調用的代碼太復雜了,下面介紹一款更簡單的方法OpenFeign。

2.OpenFeign 跨服務請求

OpenFeign 是一個聲明式的 Web 服務客戶端,它使得編寫 HTTP 客戶端變得更加簡單。它是 Netflix Feign 的增強版本,并且與 Spring Cloud 深度集成,允許開發者通過創建接口并用注解描述 HTTP 請求來定義和使用 RESTful 客戶端。這簡化了代碼的編寫,因為你不需要構建 URL、手動解析 JSON 或處理其他繁瑣的任務,對跨服務請求進行簡化了。

2.1 設計思路

為了避免重復編碼,下面有兩種抽取思路:

  • 思路1:抽取到微服務之外的公共module(適用與聚合工程)

  • 思路2:每個微服務自己抽取一個module

如圖:

方案1抽取更加簡單,工程結構也比較清晰,但缺點是整個項目耦合度偏高。(適用于maven聚合模塊中使用)

方案2抽取相對麻煩,工程結構相對更復雜,但服務之間耦合度降低。

?下面我們采用第一個思路,新建一名模板api模板,單獨存放openFeign請求

?2.2 導入依賴

  <!--openFeign--><dependency><groupId>org.springframework.cloud</groupId><artifactId>spring-cloud-starter-openfeign</artifactId></dependency><!--負載均衡器--><dependency><groupId>org.springframework.cloud</groupId><artifactId>spring-cloud-starter-loadbalancer</artifactId></dependency>

2.3 編寫Feign客戶端

import com.heima.cart.domain.dto.ItemDTO;
import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestParam;import java.util.Collection;
import java.util.List;@FeignClient("item-service") //遠程請求的服務
public interface ItemClient {@GetMapping("/items")//請求的服務路徑List<ItemDTO> queryItemByIds(@RequestParam("ids") Collection<Long> ids);
}

?2.4 啟動OpenFeign功能

在需要發送跨服務請求(即:需要用到openFeign功能模塊)的微服務的pom.xml中添加hm-api模塊,

在啟動類上添加注解@EnableFeignClients,開啟openFeign功能 ,并且指明所在客戶端的位置(類)

  • 方式1:聲明掃描包:

  • 方式2:聲明要用的API客戶端

? 將客戶端注入,發起請求

 //注入private final ItemClient itemClient;//發起請求
List<ItemDTO> items = itemClient.queryItemByIds(itemIds);

2.5 openFeign日志

默認情況下,openFeign請求中,后臺是沒有日志的,一旦出錯,很難發現。

需要手動創建config包,配置日志類

import feign.Logger;
import org.springframework.context.annotation.Bean;public class DefaultFeignConfig {@Beanpublic Logger.Level feignLogLevel(){return Logger.Level.FULL;}
}

?在啟動類中,開啟日志,

全局生效:在@EnableFeignClients中配置,針對所有FeignClient生效。

@EnableFeignClients(defaultConfiguration = DefaultFeignConfig.class)

2.6 openFeign請求頭

利用openFeign發送請求時,需要攜帶當前發起請求的用戶信息。

這里我們將用戶id放到請求頭中,轉發給另一個微服務。前端對后端發起的請求,交給網關處理,網關負責對jwt進行解析驗證。網關驗證完成后,才會轉交給其他微服務。

后續更新網關處理方案.....

import com.hmall.common.utils.UserContext;
import feign.Logger;
import feign.RequestInterceptor;
import feign.RequestTemplate;
import org.springframework.context.annotation.Bean;public class DefaultFeignConfig {@Beanpublic Logger.Level feignLogLevel(){return Logger.Level.FULL;}@Beanpublic RequestInterceptor userInfoRequestInterceptor(){return new RequestInterceptor() {@Overridepublic void apply(RequestTemplate template) {// 獲取登錄用戶Long userId = UserContext.getUser();if(userId == null) {// 如果為空則直接跳過return;}// 如果不為空則放入請求頭中,傳遞給下游微服務template.header("user-info", userId.toString());}};}
}

2.7 openFeign連接池

Feign底層發起http請求,依賴于其它的框架。其底層支持的http客戶端實現

  • HttpURLConnection:默認實現,不支持連接池

  • Apache HttpClient :支持連接池

  • OKHttp:支持連接池

因此我們通常會使用帶有連接池的客戶端來代替默認的HttpURLConnection。比如,我們使用OK Http.

導入OKHttp依賴

<!--OK http 的依賴 -->
<dependency><groupId>io.github.openfeign</groupId><artifactId>feign-okhttp</artifactId>
</dependency>

application.yml配置文件中開啟Feign的連接池功能,重啟服務,連接池就生效了。

feign:okhttp:enabled: true # 開啟OKHttp功能

下一篇

SpringCloud 入門(3)—— Nacos配置中心-CSDN博客

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/web/64110.shtml
繁體地址,請注明出處:http://hk.pswp.cn/web/64110.shtml
英文地址,請注明出處:http://en.pswp.cn/web/64110.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

解決Springboot整合Shiro自定義SessionDAO+Redis管理會話,登錄后不跳轉首頁

解決Springboot整合Shiro自定義SessionDAORedis管理會話&#xff0c;登錄后不跳轉首頁 問題發現問題解決 問題發現 在Shiro框架中&#xff0c;SessionDAO的默認實現是MemorySessionDAO。它內部維護了一個ConcurrentMap來保存session數據&#xff0c;即將session數據緩存在內存…

java歷史版本信息

Java是由Sun Microsystems&#xff08;后被Oracle公司收購&#xff09;于1995年推出的面向對象程序設計語言和Java平臺的總稱。到目前為止&#xff0c;Java已經發布了多個版本&#xff0c;以下是Java的主要版本及其發布時間。 一般來說&#xff0c;LTS版本&#xff08;長期支持…

windows nmake 安裝openssl

windows nmake 編譯和安裝 openssl 本文提供了在Windows環境下安裝OpenSSL的詳細步驟&#xff0c;包括下載Perl、NASM和VisualStudio&#xff0c;配置環境變量&#xff0c;使用PerlConfigure設置平臺&#xff0c;通過nmake進行編譯、測試和安裝。整個過程涉及32位和64位版本的選…

Spring Boot應用開發實戰:從入門到精通

一、Spring Boot 簡介 1.1 什么是 Spring Boot&#xff1f; Spring Boot 是一個開源框架&#xff0c;旨在簡化新 Spring 應用的初始搭建以及開發過程。它構建在 Spring 框架之上&#xff0c;利用了 Spring 的核心特性&#xff0c;如依賴注入&#xff08;Dependency Injection&…

一、Hadoop概述

文章目錄 一、Hadoop是什么二、Hadoop發展歷史三、Hadoop三大發行版本1. Apache Hadoop2. Cloudera Hadoop3. Hortonworks Hadoop四、Hadoop優勢1. 高可靠性2. 高擴展性3. 高效性4. 高容錯性五、Hadoop 組成1. Hadoop1.x、2.x、3.x區別2. HDFS 架構概述3. YARN 架構概述4. MapR…

python版本的Selenium的下載及chrome環境搭建和簡單使用

針對Python版本的Selenium下載及Chrome環境搭建和使用&#xff0c;以下將詳細闡述具體步驟&#xff1a; 一、Python版本的Selenium下載 安裝Python環境&#xff1a; 確保系統上已經安裝了Python 3.8及以上版本。可以從[Python官方網站]下載并安裝最新版本的Python&#xff0c;…

vue---- H5頁面 pdf,docx,excel文件預覽下載功能

vue---- H5頁面 pdf&#xff0c;docx&#xff0c;excel文件預覽&&下載功能 pdf&#xff0c;docx&#xff0c;excel文件預覽&&下載適用于vue2和vue3&#xff0c;示例為vue3 1.npm下載這些文件的插件&#xff08;選擇自己需要預覽的進行下載&#xff09; 安裝pd…

vue3和springboot使用websocket通信

前端端口&#xff1a;9090 后端端口&#xff1a;8080 vue3 引入依賴&#xff1a; npm install sockjs-client stomp/stompjs vue頁面 <template><div><h1>WebSocket 示例</h1><button click"sendMessage">發送消息</button>…

【時時三省】(C語言基礎)動態內存函數malloc

山不在高&#xff0c;有仙則名。水不在深&#xff0c;有龍則靈。 ----CSDN 時時三省 malloc 開辟內存塊 使用格式 void *malloc&#xff08;size_t sie&#xff09;&#xff1b; 示例 10*sizeof(int&#xff09;就是開辟空間的大小 如果p是void指針的話 p不能解引用 m…

c#多線程之生產者-消費者模型

在 C# 中實現 生產者-消費者模式&#xff0c;通常需要多個線程來處理數據的生產和消費。我們可以使用 Queue<T> 來作為存儲數據的隊列&#xff0c;并使用 Thread、Mutex 或 Monitor 來確保線程安全。BlockingCollection<T> 是 C# 提供的一個線程安全的集合&#xf…

選煤廠可視化技術助力智能化運營

通過圖撲 HT 可視化搭建智慧選煤廠管理平臺&#xff0c;優化了選煤生產流程&#xff0c;提高了資源利用率和安全性&#xff0c;助力企業實現智能化運營和可持續發展目標。

【論文筆記】Visual Alignment Pre-training for Sign Language Translation

&#x1f34e;個人主頁&#xff1a;小嗷犬的個人主頁 &#x1f34a;個人網站&#xff1a;小嗷犬的技術小站 &#x1f96d;個人信條&#xff1a;為天地立心&#xff0c;為生民立命&#xff0c;為往圣繼絕學&#xff0c;為萬世開太平。 基本信息 標題: Visual Alignment Pre-tra…

深入淺出 MyBatis | CRUD 操作、配置解析

3、CRUD 3.1 namespace namespace 中的包名要和 Dao/Mapper 接口的包名一致&#xff01; 比如將 UserDao 改名為 UserMapper 運行發現抱錯&#xff0c;這是因為 UserMapper.xml 中沒有同步更改 namespace 成功運行 給出 UserMapper 中的所有接口&#xff0c;接下來一一對…

前端:改變鼠標點擊物體的顏色

需求&#xff1a; 需要改變圖片中某一物體的顏色&#xff0c;該物體是純色&#xff1b; 鼠標點擊哪個物體&#xff0c;哪個物體的顏色變為指定的顏色&#xff0c;利用canvas實現。 演示案例 代碼Demo <!DOCTYPE html> <html lang"en"><head>&l…

遞歸算法常見問題(Java)

問題&#xff1a;斐波那契數列,第1項和第2項都為1&#xff0c;后面每一項都為相鄰的前倆項的和,求第n個數 解法&#xff1a;每一個數都為前倆個數之和&#xff0c;第1項和第2項都為1&#xff0c;所以寫 方法f1(n)即為求第n個數&#xff0c;那么f1(n-1)為求第n-1個數&#xff0…

git自動壓縮提交的腳本

可以將當前未提交的代碼自動執行 git addgit commitgit squash Git 命令安裝指南 1. 創建腳本目錄 如果目錄不存在&#xff0c;創建它&#xff1a; mkdir -p ~/.local/bin2. 創建腳本文件 vim ~/.local/bin/git-squash將完整的腳本代碼復制到此文件中。 3. 設置腳本權限…

C項目 天天酷跑(下篇)

上篇再博客里面有&#xff0c;接下來我們實現我們剩下要實現的功能 文章目錄 碰撞檢測 血條的實現 積分計數器 前言 我們現在要繼續優化我們的程序才可以使這個程序更加的全面 碰撞的檢測 定義全局變量 實現全局變量 void checkHit() {for (int i 0; i < OBSTACLE_C…

論文解讀——掌紋生成網絡 RPG-Palm升級版PCE-Palm

該文章是2023年論文RPG-Palm的升級版 論文&#xff1a;PCE-Palm: Palm Crease Energy Based Two-Stage Realistic Pseudo-Palmprint Generation 作者&#xff1a;Jin, Jianlong and Shen, Lei and Zhang, Ruixin and Zhao, Chenglong and Jin, Ge and Zhang, Jingyun and Ding,…

代碼隨想錄算法【Day2】

Day2 1.掌握滑動窗口法 2.模擬題&#xff0c;堅持循環不變量原則 209 長度最小的子數組 暴力法&#xff1a; class Solution { public:int minSubArrayLen(int target, vector<int>& nums) {//暴力法int i, j; //i代表起始點&#xff0c;j代表終止點int sum; //…

android——屏幕適配

一、屏幕適配的重要性 在 Android 開發中&#xff0c;屏幕適配是非常關鍵的。因為 Android 設備具有各種各樣的屏幕尺寸、分辨率和像素密度。如果沒有進行良好的屏幕適配&#xff0c;應用可能會出現顯示不完整、元素拉伸或壓縮變形、字體大小不合適等問題&#xff0c;極大地影響…