SpringCloud

发布时间 2023-12-05 23:22:47作者: 微风抚秀发

SpringCloud

小知识点 @RequiredArgsConstructor 自动创建一个包含所有被 final 修饰的属性的构造函数

Lombok 会自动为被注解的类生成构造函数,而无需手动编写

远程调用

方案一 RestTemplate

多个项目之间 无法直接调用,

Spring 提供 RestTemplate工具,可以方便的实现Http请求的发送。

使用步骤如下:注入RestTemplate到Spring容器

首先 在启动类 注入 RestTemplate

其次 在需要使用 远程调用的方法中

方案二 Nacos注册中心

linux 配置nacos

自备资料传到linux root目录下

加载

docker load -i nacos.tar

进入root目录,然后执行docker命令 创建并启动nacos(后台运行)

docker run -d \
--name nacos \
--env-file ./nacos/custom.env \
-p 8848:8848 \
-p 9848:9848 \
-p 9849:9849 \
--restart=always \
nacos/nacos-server:v2.1.0-slim

启动完成后,访问下面地址:http://虚拟机ip:8848/nacos/

初始账号密码 nacos

服务注册
添加依赖
<!--nacos 服务注册发现-->
<dependency>
    <groupId>com.alibaba.cloud</groupId>
    <artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
</dependency>
配置Nacos

application.yml中添加nacos地址配置:

spring:
  application:
    name: item-service # 服务名称
  cloud:
    nacos:
      server-addr: 192.168.233.110:8848 # nacos地址

调用服务
引入依赖
<!--nacos 服务注册发现-->
<dependency>
    <groupId>com.alibaba.cloud</groupId>
    <artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
</dependency>
配置Nacos
spring:
  application:
    name: item-service # 服务名称
  cloud:
    nacos:
      server-addr: 192.168.233.110:8848 # nacos地址

这里采用 随机负载均衡

//        2查询商品
//      2.1. 根据 服务名字 拉取 服务的实例列表
        List<ServiceInstance> instances = discoveryClient.getInstances("item-service");
//        判断 是否 为空 为空直接返回
        if (CollUtils.isEmpty(instances)){
            return;
        }
//        2.2. 选用 负载均衡 算法 挑选实例
        ServiceInstance instance = instances.get(RandomUtil.randomInt(instances.size()));
//        2.3. 获取 实例的 ip 和 端口
        URI uri = instance.getUri();

方案3 OpenFeign 让远程调用像本地方法调用一样简单(优雅)

利用nacos 远程调用依旧繁琐,这里使用 OpenFeign 技术

openfeign默认使用的是ribbon组件做负载均衡的,现在引入了loadbalancer组件,负载均衡组件大部分默认使用的都是轮询策略

引入依赖

在 调用服务 的pom.xml中引入OpenFeign的依赖和loadBalancer依赖:

  <!--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>
启用OpenFeign

调用者 cart-service的 启动类上添加注解,启动OpenFeign功能:

@EnableFeignClients
编写OpenFeign客户端

在 调用者 服务层 ,定义一个新的接口,编写Feign客户端:

package com.hmall.cart.client;

import com.hmall.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);
}

这里只需要声明接口,无需实现方法。接口中的几个关键信息:

  • @FeignClient("item-service") :声明 被调用 的服务名称
  • @GetMapping :声明请求方式
  • @GetMapping("/items") :声明请求路径
  • @RequestParam("ids") Collection<Long> ids :声明请求参数
  • List<ItemDTO> :返回值类型

有了上述信息,OpenFeign就可以利用动态代理帮我们实现这个方法,并且向http://item-service/items发送一个GET请求,携带ids为请求参数,并自动将返回值处理为List<ItemDTO>

我们只需要直接调用这个方法,即可实现远程调用了

使用FeignClient 实现远程调用
private void handleCartItems(List<CartVO> vos) {
        // 1.获取商品id  sku商品id
        Set<Long> itemIds = vos.stream().map(CartVO::getItemId).collect(Collectors.toSet());
//        2查询商品   OpenFeign远程调用
        List<ItemDTO> items = itemClient.queryItemByIds(itemIds);
        if (CollUtils.isEmpty(items)) {
            return;
        }
        // 3.转为 id 到 item的map 将查询到的购物车所有商品存到map中 id--商品项
        Map<Long, ItemDTO> itemMap = items.stream().collect(Collectors.toMap(ItemDTO::getId, Function.identity()));
        // 4.写入vo
        for (CartVO v : vos) {
//            通过id 获取 map集合中 商品的最新信息
            ItemDTO item = itemMap.get(v.getItemId());
            if (item == null) {
                continue;
            }
//            设置 购物车中所有商品的最新 价格,状态,库存量
            v.setNewPrice(item.getPrice());
            v.setStatus(item.getStatus());
            v.setStock(item.getStock());
        }
    }