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.mzph.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;极大地影响…