hmall-微服务开发

说明:目前SpringCloud最新版本为2022.0.x版本,对应的SpringBoot版本为3.x版本,但它们全部依赖于JDK17,目前在企业中使用相对较少。推荐使用次新版本:Spring Cloud 2021.0.x以及Spring Boot 2.7.x版本。(注意:该项目使用jdk版本是11,亲测jdk17运行不了)

1. 拆分商品、购物车服务

1. 创建新module - maven模块,并引入依赖

2. 新建包com.hmall.xx(业务名),添加和修改启动类,新建mapper包、domain包 - service包 - controller包

3. 拷贝并修改yaml配置文件到resources中,分别修改 端口号、服务名称、datasource(需创建sql datebase)、swagger接口文档说明与controller扫描包

4. 添加以下部分代码

1)domain包代码:dto、po、vo、(query)

2)mapper包代码 :mapper接口 及mapper.xml文件

3) service包:service接口及实现类

4)controller包

5. 刷新maven,添加该业务模块启动项到Services中,并把Active profiles 修改为 local

6. 运行,在访问地址后面添加doc.html访问swagger接口文档,进行调试

具体步骤参考:Docs

1.1 商品服务

在hmall下new module:(IDEA版本不一致跟文档中的创建有一定出入)

注意:在application.yaml文件中修改了端口号,数据库名称,接口文档设置

根据文档完成操作之后,启动 item-service,访问商品微服务的swagger接口文档:http://localhost:8081/doc.html

至此,商品服务拆分完成。

1.2 购物车拆分

在hmall下new module:

创建完后,pom.xml文件是橙色,代表idea没有识别到该项目为maven项目,pom.xml–>右键–>add as maven project即可。

在pom.xml文件导入依赖,与文档中创建module不同(文档里IDEA可以直接创建Maven,并且指定父工程),虽然按照如上步骤创建,父工程是默认的,但是可以直接在pom.xml文件修改。

 根据文档完成操作之后,启动 cart-service,访问购物车微服务的swagger接口文档:http://localhost:8082/doc.html

把User写死,查询购物车数据成功。

1.3 服务调用

在购物车业务中需要查询商品信息,但商品信息查询的逻辑全部迁移到了item-service,导致无法查询。最终结果就是查询到的购物车数据不完整,为了解决这个问题,需要把原本本地方法调用,改造成跨微服务的远程调用(RPC,即Remote Produce Call)。

类比前端向服务端查询数据,其实就是从浏览器远程查询服务端数据。比如通过Swagger测试商品查询接口,就是向http://localhost:8081/items这个接口发起的请求。通过http请求的方式,可以完成远程查询、实现新增、删除等各种远程请求。

1.3.1 RestTemplate

Spring提供了一个RestTemplate的API,可以方便的实现Http请求的发送。

Java发送http请求可以使用Spring提供的RestTemplate,使用的基本步骤如下:

  • 注册RestTemplate到Spring容器

  • 调用RestTemplate的API发送请求,常见方法有:

    • getForObject:发送Get请求并返回指定类型对象

    • PostForObject:发送Post请求并返回指定类型对象

    • put:发送PUT请求

    • delete:发送Delete请求

    • exchange:发送任意类型请求,返回ResponseEntity

编写远程调用逻辑代码后,直接启动cart-service,测试查询购物车:

出现这个错误是因为没有启动item-service的服务。启动item-service服务后,重新测试,查询成功:

1.4 服务注册和发现

如果商品微服务调用较多,为了应对高并发,进行了多实例部署,每个item-service的实例IP或端口不同:

  • item-service这么多实例,cart-service如何知道每一个实例的地址?

  • http请求要写url地址,cart-service服务到底该调用哪个实例呢?

  • 如果在运行过程中,某一个item-service实例宕机,cart-service依然在调用该怎么办?

  • 如果并发太高,item-service临时多部署了N台实例,cart-service如何知道新实例的地址?

1.4.1 注册中心原理

在微服务远程调用的过程中,包括两个角色:

  • 服务提供者:提供接口供其它微服务访问,比如item-service

  • 服务消费者:调用其它微服务提供的接口,比如cart-service

流程如下:

  • 服务启动时就会注册自己的服务信息(服务名、IP、端口)到注册中心

  • 调用者可以从注册中心订阅想要的服务,获取服务对应的实例列表(1个服务可能多实例部署)

  • 调用者自己对实例列表负载均衡,挑选一个实例

  • 调用者向该实例发起远程调用

当服务提供者的实例宕机或者启动新实例时,调用者如何得知呢?

  • 服务提供者会定期向注册中心发送请求,报告自己的健康状态(心跳请求)

  • 当注册中心长时间收不到提供者的心跳时,会认为该实例宕机,将其从服务的实例列表中剔除

  • 当服务有新实例启动时,会发送注册服务请求,其信息会被记录在注册中心的服务实例列表

  • 当注册中心服务列表变更时,会主动通知微服务,更新本地服务列表

1.4.2 Nacos注册中心

目前开源的注册中心框架有很多,国内比较常见的有:

  • Eureka:Netflix公司出品,目前被集成在SpringCloud当中,一般用于Java应用

  • Nacos:Alibaba公司出品,目前被集成在SpringCloudAlibaba中,一般用于Java应用

  • Consul:HashiCorp公司出品,目前集成在SpringCloud中,不限制微服务语言

文档中,直接使用Docker拉取镜像run nacos,我在本机操作也没有docker。步骤如下:

1)下载nacos:
Release 2.1.0 (Apr 29, 2022) · alibaba/nacos · GitHub

2)打开nacos安装路径,bin/startup.cmd,找到set MODE = "",把值修改为standalone(修改启动方式为单机启动)

3)双击启动

4)访问http://localhost:8848/nacos/     账号密码都是nacos

1.4.3 服务注册

接下来,我们把item-service注册到Nacos,步骤如下:

  • 引入依赖

  • 配置Nacos地址

  • 重启

为了测试一个服务的多个实例的情况,在配置一个item-service的部署实例,重命名并配置新的端口:

配置完成后启动服务,报错

ERROR 12176 --- [t.remote.worker] c.a.n.c.remote.client.grpc.GrpcClient    : Server check fail, please check server 127.0.0.1 ,port 9848 is available , error ={}

问题原因:项目总使用的Nacos客户端是2.x版本以上,Nacos在这个版本中新增了gRPC通信,默认通信端口是Nacos的server-adddr的端口号加上1000的偏移量,所以报错会检查9848端口是否开放。

网上有很多的解决方案,五花八门。具体可见:springCloud 连接nacos报错Server check failport 9848 error={} 解决方案_server check fail, please check server 192.168.209-CSDN博客

方案一:检查nacos服务端与spingcloud服务器之间的网络,保障nacos服务端对外端口8848、9848、7848、9849及网络均可访问(telnet验证)。

1)Windows netstat -ano | findstr :9848查看被占用的端口,打开cmd以管理员身份运行,使用 netstat -ano | findstr :9848 命令。发现并没被占用。

2)在Windows上启用telnet客户端:

  • 打开控制面板。
  • 选择“程序”。
  • 点击“打开或关闭Windows功能”。
  • 在弹出的窗口中找到“Telnet客户端”,勾选并点击“确定”。

3)检查Nacos服务器的8848端口: 打开命令提示符(cmd),输入以下命令:

telnet 127.0.0.1 8848

连接成功,屏幕会变空白,表示可以访问端口。按 Ctrl + ],然后输入quit退出。

4)检查Nacos服务器的9848端口(如果使用9848):

telnet 127.0.0.1 9848

同样,连接成功,屏幕会变空白,表示可以访问端口。

明明都能访问,但是还是连不上,这个方案我搞不来。

方案2:在版本说明 · alibaba/spring-cloud-alibaba Wiki · GitHub查看对应版本,下载对应的Nocos客户端。我真的很呆,在自己本机上电脑下的叫服务端,项目依赖的是客户端!!!服务端(server)2.x向下兼容客户端(client)1.x版本,客户端(client)2.x版本无法使用服务端(server)1.x版本。
Three hours later... ....

我也不知道怎么回事鬼使神差的就成功了, 还试过新建一个bootstrap.yaml,在该配置文件下配置nacos。说是要优先其他配置进行配置啥的(具体见:nacos必须在bootstrap.yml文件中配置,在application-dev.yml文件中会报异常的问题 · Issue #7290 · alibaba/nacos · GitHub(完美解决)Connection refused: no further information: /127.0.0.1:9848_cloud启动 no further information-CSDN博客)。但是后面我就想知道走到哪一步才成功的,我就把他删掉了,发现还是成功了。
解决:
item-service服务下application.yaml配置文件:

虽然也有ERROR,但是服务能正常启动,并且能在服务列表正常显示。后面复制item-service服务启动不成功,检查是防火墙和网络的问题,再重新启动成功,两个服务都注册成功。(哪有不疯的程序员呢~)

1.4.4 服务发现

服务的消费者要去nacos订阅服务,这个过程就是服务发现,步骤如下:

  • 引入依赖

  • 配置Nacos地址

  • 发现并调用服务

使用swagger文档测试查询购物车,有时候会因为翻墙和网络原因500错误,注意一点!!!

可以看到此次查询走的itemServiceApplication2

1.5 OpenFeign

远程调用的关键点就在于四个:

  • 请求方式

  • 请求路径

  • 请求参数

  • 返回值类型

OpenFeign利用SpringMVC的相关注解来声明上述4个参数,然后基于动态代理来生成远程调用的代码,而无需手动编写,非常方便。

1.5.1 引入依赖

在cart-service服务的pom.xml中引入OpenFeign的依赖和loadblancer依赖:

  <!--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>

1.5.2 启用OpenFeign

接下来,我们在cart-service的启动类上添加注解@EnableFeignClients,启动OpenFeign功能:

1.5.3 编写OpenFeign客户端

在cart-service中,定义一个新的接口,编写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.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>

1.5.4 使用FeignCilent

1.5.5 连接池

Feign底层发起http请求,依赖于其它的框架。其底层支持的http客户端实现包括:

  • HttpURLConnection:默认实现,不支持连接池

  • Apache HttpClient :支持连接池

  • OKHttp:支持连接池

通常会使用带有连接池的客户端来代替默认的HttpURLConnection。比如,使用OK Http。

按照文档,引入依赖,开启连接池。

在swagger文档调试:

1.5.6 抽取Feign客户端

为了避免重复编码的办法就是抽取。可以将公共代码抽取到微服务之外的公共module。

在hmall下定义一个新的module,命名为hm-api,导入依赖。

将ItemDTO和ItemClient都拷贝进hm-api。任何微服务要调用item-service中的接口,只需要在pom.xml引入hm-api模块依赖即可,无需自己编写Feign客户端了。

注意!!!要记得在微服务的启动类的类上声明扫描包。

2. 拆分微服务的其他模块

2.1 用户模块

目录结构如下:

记得要开启nacos,才能运行成功。记得yaml文件改成自己的nacos地址。

启动项目后,访问 http://localhost:8084/doc.html,测试登陆接口,200成功。

2.2 交易模块

根据文档创建模块,目录结构:

对hm-api做出对应的修改:

有一个要注意的地方,OrderServiceImpl会报错:

报错就是说OrderFormDTO的getDetails方法返回的类型是com.hmall.trade.domain.dto.OrderDetailDTO但是左侧接收的参数类型是com.hmall.api.dto.OrderDetailDTO,所以报错。不知道还有没有什么高明的解决办法,我直接更改在trade-service下的com/hmall/trade/domain/dto/OrderFormDTO.java,报错消失。

启动项目后,在http://localhost:8085/doc.html 查询1654779387523936258订单号,测试接口200成功。

2.3 支付模块

目录结构:

hm-api新增远程调用client

启动项目后,在http://localhost:8086/doc.html 查询支付订单,测试接口200成功。

  • 29
    点赞
  • 19
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值