当前位置: 首页 > news >正文

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.mrgr.cn/news/81172.html

相关文章:

  • 如何在 QGIS 中打开 Esri 文件地理数据库(GDB)
  • Java Web开发基础——Web应用的请求与响应机制
  • dockerfile文档编写(1):基础命令
  • [蓝桥杯 2013 省 AB] 错误票据
  • *【每日一题 提高题】[蓝桥杯 2022 国 A] 选素数
  • 【笔记 未完】学校教的ssh:远程连接到另一个电脑 并对其进行操作
  • 访谈积鼎科技总经理:国产CFD软件发展与未来趋势展望
  • GitCode 光引计划投稿|JavaVision:引领全能视觉智能识别新纪元
  • Centos7安装k8s集群
  • node.js的异步工作之---回调函数与回调地狱
  • Pandas系列|第三期:Pandas中访问数据
  • 2024年A股最新退市规则
  • linux上抓包RoCEv2
  • Day1 苍穹外卖前端 Vue基础、Vue基本使用方式、Vue-router、Vuex、TypeScript
  • 【学术小白的学习之路】基于情感词典的中文句子情感分析(代码词典获取在结尾)
  • FPGA学习(基于小梅哥Xilinx FPGA)学习笔记
  • YoloV8改进策略:Head改进|DynamicHead,利用注意力机制统一目标检测头部|即插即用
  • sqlite 自定以脚本解释器
  • 时空信息平台架构搭建:基于netty封装TCP通讯模块(IdleStateHandler网络连接监测,处理假死)
  • UE5 渲染管线 学习笔记
  • 【Rust自学】6.1. 定义枚举
  • 设计模式七大原则
  • idea2024创建JavaWeb项目以及配置Tomcat详解
  • 达梦数据库-单机部署
  • Nvidia环境配置again—cuda、cudnn、TensorRT
  • Linux运维常见命令