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

Java研学-SpringCloud(四)

五 远程调用

1 创建模型层 – model

  各个微服务的实体类模型只存在于自己的服务中,当相互调用时,每个服务的模型,可能都被其他微服务所需要,因此抽取model层,所有实体类模型都在这里。位于父工程下。
在这里插入图片描述

2 导入模型

  ① 复制订单与商品实体模型到模型层后,删除每个微服务的实体类模型,此后微服务统一依赖模型层,其中囊括了所有数据模型,便于交叉调用,而微服务本身不需要再定义实体类模型。
在这里插入图片描述
② 导入lombok依赖 – model.pom

    <dependencies><dependency><groupId>org.projectlombok</groupId><artifactId>lombok</artifactId><scope>annotationProcessor</scope></dependency></dependencies>

  ③ 微服务都需要模型层,因此将model导入service依赖中 – services.pom

        <dependency><groupId>cn.tj</groupId><artifactId>model</artifactId><version>0.0.1-SNAPSHOT</version></dependency>

3 新增配置类 – service-product ,service-order

  为了给远程发送数据,Spring提供了组件RestTemplate他是线程安全的,不需要每次使用都new,因此创建配置类后,通过注入的方式获取
在这里插入图片描述
① ProductServiceConfig

@Configuration
public class ProductServiceConfig {// 放入容器中 想用直接调@Beanpublic RestTemplate restTemplate() {return new RestTemplate();}
}

  ② OrderServiceConfig配置类

@Configuration
public class OrderServiceConfig {// 放入容器中 想用直接调@Beanpublic RestTemplate restTemplate() {return new RestTemplate();}
}

4 远程调用方法 – OrderServiceImpl

@Slf4j
@Service
public class OrderServiceImpl implements OrderService {@AutowiredDiscoveryClient discoveryClient;@AutowiredRestTemplate restTemplate;@Overridepublic Order createOrder(Long productId, Long userId) {// 远程调用获取商品数据Product product = getProductFromRemote(productId);Order order = new Order();order.setId(1L);// 总金额 = 商品单价 * 数量order.setTotalAmount(product.getPrice().multiply(new BigDecimal(product.getNum())));order.setUserId(userId);order.setNickname("huang");order.setAddress("涠洲岛");// 远程查询商品列表order.setProductlist(Arrays.asList(product));return order;}// 远程调用获取商品数据方法private Product getProductFromRemote(Long productId) {// 通过注册中心获取存在商品服务的所有地址(根据对方微服务的名字)List<ServiceInstance> instances = discoveryClient.getInstances("service-product");// 取第一个实例 随意取的ServiceInstance instance = instances.get(0);// 远程URL 获取ip端口String url="http://"+instance.getHost()+":"+instance.getPort()+"/product/"+productId;// 日志记录log.info("远程请求:{}",url);// 将返回的 json转为 Product实体Product product = restTemplate.getForObject(url, Product.class);return product;}
}

5 精确订单实体类模型层 – Order

public class Order {private Long id;private BigDecimal totalAmount;private Long userId;private String nickname;private String address;// Object 改为 Productprivate List<Product> productlist;
}

6 订单调用商品测试

在这里插入图片描述
在这里插入图片描述

7 若有服务下线

  复制ProductMainApplication启动9001端口
由于订单服务每次调用前都会询问注册中心,获取商品服务的所有地址,从中挑选一个进行调用,若有服务器实例宕机下线,注册中心就不会存在该实例,获取的地址列表取第一个也不会取到宕机的服务器地址,通过其他服务器实例完成调用
在这里插入图片描述

六 负载均衡

  每次都取地址列表的第一个,就会一直给一个固定的服务器地址发送远程调用,不能够合理利用服务器资源,此时需要使用负载均衡

1 引入负载均衡依赖 – service-order.pom

        <dependency><groupId>org.springframework.cloud</groupId><artifactId>spring-cloud-starter-loadbalancer</artifactId></dependency>

2 测试类 – LoadbalancerTest

@SpringBootTest
public class LoadbalancerTest {// 负载均衡组件API@AutowiredLoadBalancerClient loadBalancerClient;@Testpublic void testLoadbalancer() {// DiscoveryClient 是获取所有实体 但负载均衡需自己负责// 选择某一个微服务的地址 返回单个实体 轮询规则ServiceInstance choose = loadBalancerClient.choose("service-product");System.out.println("choose: " + choose.getServiceId() + "; " + choose.getHost() + "; " + choose.getPort());choose = loadBalancerClient.choose("service-product");System.out.println("choose: " + choose.getServiceId() + "; " + choose.getHost() + "; " + choose.getPort());choose = loadBalancerClient.choose("service-product");System.out.println("choose: " + choose.getServiceId() + "; " + choose.getHost() + "; " + choose.getPort());choose = loadBalancerClient.choose("service-product");System.out.println("choose: " + choose.getServiceId() + "; " + choose.getHost() + "; " + choose.getPort());}
}
// 测试结果 轮询
choose: service-product; 192.168.44.1; 9000
choose: service-product; 192.168.44.1; 9001
choose: service-product; 192.168.44.1; 9000
choose: service-product; 192.168.44.1; 9001

3 改造负载均衡的远程调用方法 – OrderServiceImpl

@Slf4j
@Service
public class OrderServiceImpl implements OrderService {@AutowiredDiscoveryClient discoveryClient;@AutowiredRestTemplate restTemplate;// 使用负载均衡组件@AutowiredLoadBalancerClient loadBalancerClient;@Overridepublic Order createOrder(Long productId, Long userId) {// 远程调用获取商品数据Product product = getProductFromRemoteWithLoadBalancer(productId);Order order = new Order();order.setId(1L);// 总金额 = 商品单价 * 数量order.setTotalAmount(product.getPrice().multiply(new BigDecimal(product.getNum())));order.setUserId(userId);order.setNickname("huang");order.setAddress("涠洲岛");// 远程查询商品列表order.setProductlist(Arrays.asList(product));return order;}// 负载均衡远程调用获取商品数据private Product getProductFromRemoteWithLoadBalancer(Long productId) {// 通过注册中心以负载均衡方式获取存在商品服务的地址ServiceInstance choose = loadBalancerClient.choose("service-product");// 远程URL 获取ip端口String url="http://"+choose.getHost()+":"+choose.getPort()+"/product/"+productId;// 日志记录log.info("远程请求:{}",url);// 将返回的 json转为 Product实体Product product = restTemplate.getForObject(url, Product.class);return product;}
}

4 多次测试 – F5

在这里插入图片描述
在这里插入图片描述

5 注解式负载均衡 – OrderServiceConfig

  将@OrderServiceConfig注解贴到RestTemplate远程调用上,即可实现负载均衡

@Configuration
public class OrderServiceConfig {// 注解式负载均衡@LoadBalanced@Beanpublic RestTemplate restTemplate() {return new RestTemplate();}
}

6 改造负载均衡方法 – OrderServiceImpl

@Slf4j
@Service
public class OrderServiceImpl implements OrderService {// 远程调用@AutowiredDiscoveryClient discoveryClient;@AutowiredRestTemplate restTemplate;@Overridepublic Order createOrder(Long productId, Long userId) {// 远程调用获取商品数据Product product = getProductFromRemoteWithLoadBalancerAnnotation(productId);Order order = new Order();order.setId(1L);// 总金额 = 商品单价 * 数量order.setTotalAmount(product.getPrice().multiply(new BigDecimal(product.getNum())));order.setUserId(userId);order.setNickname("huang");order.setAddress("涠洲岛");// 远程查询商品列表order.setProductlist(Arrays.asList(product));return order;}// 注解负载均衡远程调用获取商品数据private Product getProductFromRemoteWithLoadBalancerAnnotation(Long productId) {// ip与端口号通过微服务名称进行动态替换// restTemplate在发送远程调用前会动态的将服务名称替换为ip与端口号String url="http://service-product/product/"+productId;// 日志记录log.info("远程请求:{}",url);// 将返回的 json转为 Product实体Product product = restTemplate.getForObject(url, Product.class);return product;}
}

7 测试注解式负载均衡

  测试是哪个商品微服务被调用 – ProductController

@RestController
public class ProductController {@AutowiredProductService productService;// 根据ID获取商品数据@GetMapping("/product/{id}")public Product getProduct(@PathVariable("id") Long productId) {// 查看控制台是否按照负载均衡进行输出System.out.println("welcome");Product product=productService.getProductById(productId);return  product;}
}

在这里插入图片描述

七 实例缓存

1 介绍

  该流程实际是发送了两次请求,1.请求注册中心获取对方服务地址,2.给对方服务地址发送请求,很是消耗性能,因此引入实例缓存
在这里插入图片描述
第一次远程调用到注册中心拿到所有上线实例的服务地址后,存入实例缓存,之后的调用从实例缓存中选择 ip和端口号 发送请求即可,而实例缓存需要和注册中心进行实时同步,若有服务下线,注册中心将数据同步给实例缓存
在这里插入图片描述
此时若注册中心宕机,面对之前调用过的服务,可以继续调用(实例缓存中有地址),没调用过的服务(未经过第一次调用),则无法访问。

2 测试

  关闭Nacos依旧可以继续进行调用
在这里插入图片描述
重启Nacos,重启服务,所有实例上线后关闭Nacos,进行第一次调用
在这里插入图片描述
报500异常,微服务没有可用的实例
在这里插入图片描述

http://www.lryc.cn/news/621491.html

相关文章:

  • Flink Stream API 源码走读 - keyBy
  • 转换一个python项目到moonbit,碰到报错输出:编译器对workflow.mbt文件中的类方法要求不一致的类型注解,导致无法正常编译
  • Vue响应式系统在超大型应用中的性能瓶颈
  • 中年海尔,是时候押注新方向了
  • 训练大模型的前提:数据治理工程:从原始数据到高质量语料的系统化治理实践
  • 抽奖程序web程序
  • 小迪安全v2023学习笔记(六十二讲)—— PHP框架反序列化
  • 实战 AI8051U 音视频播放:USART-SPI→DMA-P2P→SPI+I2S 例程详解
  • Redis 实用型限流与延时队列:从 Lua 固定/滑动窗口到 Streams 消费组(含脚本与压测)
  • 大华相机RTSP无法正常拉流问题分析与解决
  • (Arxiv-2025)Stand-In:一种轻量化、即插即用的身份控制方法用于视频生成
  • openwrt增加自定义网页
  • 基于asp.net#C##VUE框架的独居老人物资配送系统的设计与实现#sql server#visual studio
  • 国内多光谱相机做得好的厂家有哪些?-多光谱相机品牌厂家
  • 8月4日实训考察:重庆五一职院走进成都国际影像产业园
  • Flink面试题及详细答案100道(1-20)- 基础概念与架构
  • 基于.net、C#、asp.net、vs的保护大自然网站的设计与实现
  • Vue3中的ref与reactive全面解析:如何正确选择响应式声明方式
  • java 策略模式 demo
  • 基于微信小程序的家教服务平台的设计与实现/基于asp.net/c#的家教服务平台/基于asp.net/c#的家教管理系统
  • 「iOS」————APP启动优化
  • 什么是接口?PHP如何使用 SessionHandlerInterface 接口实现Session自定义会话数据存储
  • Spark 运行流程核心组件(二)任务调度
  • Python 基础语法笔记.2
  • Dijkstra与Floyd求最短路算法简介
  • zabbix部署问题后常见问题
  • sqli-labs通关笔记-第50关 GET数值型order by堆叠注入(手工注入+脚本注入两种方法)
  • StringBoot-SSE和WebFlux方式消息实时推送-默认单向-可增加交互接口
  • qt项目中解决关闭弹窗后执行主界面的信号槽时闪退问题
  • c++中的Lambda表达式详解