image.png

组件选择

注册中心:SpringCloud Alibaba Nacos
配置中心:SpringCloud Alibaba Nacos
负载均衡:SpringCloud Ribbon
声明式HTTP客户端:SpringCloud Feign ——调用远程服务
负载均衡:SpringCloud Ribbon —— feign中已经整合,无需显示引用
服务容错:SpringCloud Alibaba Sentinel ——限流、降级、熔断
API网关:SpringCloud Gateway ——webflux 编程模式
调用链路监控:SpringCloud Sleuth
分布式事务:SpringCloud Alibaba Seata ——原Fescar
image.png

版本选择

参考:官方

image.png

下载 Nacos Server

下载地址:Github Release 由上面版本选择可知:当前对应 Nacos 版本为1.2.1

下载对应系统的tar包(Linux)或者zip包(Windows),解压后运行bin目录下的可执行文件即可运行Nacos

Docker启动nacos

  1. docker run --name nacos -d -p 8848:8848 --privileged=true \
  2. --restart=always \
  3. -e JVM_XMS=512m \
  4. -e JVM_XMX=2048m \
  5. -e MODE=standalone \
  6. -e PREFER_HOST_MODE=hostname \
  7. -v /home/nacos/logs:/home/nacos/logs \
  8. nacos/nacos-server:1.2.1

项目中进行微服务版本管理

父pom引入上面对应版本的依赖:

  1. <properties>
  2. <spring.boot.version>2.2.5.RELEASE</spring.boot.version>
  3. <spring.cloud.version>Hoxton.SR3</spring.cloud.version>
  4. <cloud.alibaba.version>2.2.1.RELEASE</cloud.alibaba.version>
  5. </properties>
  6. <dependencyManagement>
  7. <dependencies>
  8. <dependency>
  9. <groupId>org.springframework.boot</groupId>
  10. <artifactId>spring-boot-dependencies</artifactId>
  11. <version>${spring.boot.version}</version>
  12. <type>pom</type>
  13. <scope>import</scope>
  14. </dependency>
  15. <dependency>
  16. <groupId>org.springframework.cloud</groupId>
  17. <artifactId>spring-cloud-dependencies</artifactId>
  18. <version>${spring.cloud.version}</version>
  19. <type>pom</type>
  20. <scope>import</scope>
  21. </dependency>
  22. <dependency>
  23. <groupId>com.alibaba.cloud</groupId>
  24. <artifactId>spring-cloud-alibaba-dependencies</artifactId>
  25. <version>${cloud.alibaba.version}</version>
  26. <type>pom</type>
  27. <scope>import</scope>
  28. </dependency>
  29. </dependencies>
  30. </dependencyManagement>

引入Nacos作为注册中心

商品、订单等模块配置Nacos类似,以商品模块为例:

1. common模块引入nacos-discovery依赖

  1. <dependency>
  2. <groupId>com.alibaba.cloud</groupId>
  3. <artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
  4. </dependency>

2. yaml文件增加配置

  1. spring:
  2. application:
  3. name: mall-product
  4. cloud:
  5. nacos:
  6. discovery:
  7. server-addr: 192.168.163.131:8848

3. 主启动类增加注解

  1. @MapperScan("com.zsy.product.dao")
  2. @SpringBootApplication
  3. @EnableDiscoveryClient
  4. public class MallProductApplication {
  5. public static void main(String[] args) {
  6. SpringApplication.run(MallProductApplication.class, args);
  7. }
  8. }

此时,启动Nacos,运行主启动类启动服务后,在浏览器打开配置文件中的地址:127.0.0.1:8848/nacos (账号密码:nacos/nacos)中就可以看到当前服务已经注册到 Nacos 服务列表中

其他服务以同样方式配置即可

引入Feign远程服务调用

商品、订单等模块配置Nacos类似,

1. common引入Feign依赖

  1. <dependency>
  2. <groupId>org.springframework.cloud</groupId>
  3. <artifactId>spring-cloud-starter-openfeign</artifactId>
  4. </dependency>

2. 主启动类开启远程调用功能

  1. @EnableFeignClients(basePackages = "com.zsy.member.feign")
  2. @EnableDiscoveryClient
  3. @SpringBootApplication
  4. public class MallMemberApplication {
  5. public static void main(String[] args) {
  6. SpringApplication.run(MallMemberApplication.class, args);
  7. }
  8. }

3. 远程调用过程测试

以优惠券模块coupon为例:当前测试member模块远程调用coupon模块

1. coupon模块接口定义

  1. @RestController
  2. @RequestMapping("coupon/coupon")
  3. public class CouponController {
  4. @RequestMapping("/member/list")
  5. public R membercoupons() {
  6. CouponEntity couponEntity = new CouponEntity();
  7. couponEntity.setCouponName("满100减10");
  8. return R.ok().put("coupons", Arrays.asList(couponEntity));
  9. }
  10. }

2. member定义远程调用接口

  1. 首先在接口上加上@FeignClient注解声明要调用哪个服务
  2. 定义接口方法,并声明要调用服务接口的地址 @RequestMapping(“/coupon/coupon/member/list”)

当前接口方法的的含义:当前服务调用该方法,会到服务注册中心找到 mall-coupon 服务,去调用该服务的/coupon/coupon/member/list 请求对应的方法。

  1. @FeignClient("mall-coupon")
  2. public interface CouponFeignService {
  3. @RequestMapping("/coupon/coupon/member/list")
  4. R memberCoupons();
  5. }

3. member 定义请求调用第2步的接口方法

  1. @RestController
  2. @RequestMapping("member/member")
  3. public class MemberController {
  4. @Autowired
  5. CouponFeignService couponFeignService;
  6. @RequestMapping("/coupons")
  7. public R test() {
  8. MemberEntity memberEntity = new MemberEntity();
  9. memberEntity.setNickname("张三");
  10. R membercoupons = couponFeignService.memberCoupons();
  11. return R.ok().put("member", memberEntity).put("coupons", membercoupons.get("coupons"));
  12. }
  13. }

4. 启动member和coupon服务完成调用

解析:

  1. 当前请求member服务的 /member/member/coupons 请求;
  2. 会调用couponFeignService.memberCoupons()
  3. 此时会到服务注册中心找到 mall-coupon 服务;
  4. 调用该服务的/coupon/coupon/member/list 请求对应的方法。

    引入Nacos作为配置中心

    参考:官方介绍

1. common模块引入nacos-config依赖

  1. <dependency>
  2. <groupId>com.alibaba.cloud</groupId>
  3. <artifactId>spring-cloud-starter-alibaba-nacos-config</artifactId>
  4. </dependency>

2. 在服务模块新建bootstrap.yaml配置 Nacos Config 元数据

此处以coupon服务为例:

  1. spring:
  2. application:
  3. name: mall-coupon
  4. cloud:
  5. nacos:
  6. config:
  7. server-addr: 192.168.163.131:8848
  8. file-extension: yaml

3. 测试读取配置中心配置

给配置中心新增一个配置

image.png

新建接口读取配置

CouponController.java
@RefreseScope:动态刷新,修改配置中心配置不需要重新启动项目

  1. @RefreshScope
  2. @RestController
  3. @RequestMapping("coupon/coupon")
  4. public class CouponController {
  5. @Autowired
  6. private CouponService couponService;
  7. @Value("${coupon.user.name}")
  8. private String name;
  9. @Value("${coupon.user.age}")
  10. private Integer age;
  11. @RequestMapping("/test")
  12. public R test() {
  13. return R.ok().put("name", name).put("age", age);
  14. }
  15. }

请求 /coupon/coupon/test 可以看到配置中心的数据,修改配置中心的配置,刷新可自动更新

Nacos 命名空间

为了对不同服务之间进行配置隔离,这里为每个微服务创建自己的命名空间。
image.png
后端代码中在bootstrap.yaml 配置属于自己服务的命名空间

  1. spring:
  2. application:
  3. name: mall-product
  4. cloud:
  5. nacos:
  6. config:
  7. server-addr: 192.168.163.131:8848
  8. file-extension: yaml
  9. namespace: 342c6ec6-2bc8-4211-b764-712180d992a8

引入Gateway作为API网关

参考:官网

创建网关子模块mall-gateway

pom.xml

  1. <?xml version="1.0" encoding="UTF-8"?>
  2. <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  3. xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
  4. <parent>
  5. <artifactId>guli-mall</artifactId>
  6. <groupId>com.zsy</groupId>
  7. <version>0.0.1-SNAPSHOT</version>
  8. </parent>
  9. <modelVersion>4.0.0</modelVersion>
  10. <artifactId>mall-gateway</artifactId>
  11. <version>0.0.1-SNAPSHOT</version>
  12. <description>API网关</description>
  13. <name>mall-gateway</name>
  14. <dependencies>
  15. <dependency>
  16. <groupId>com.zsy</groupId>
  17. <artifactId>mall-common</artifactId>
  18. <exclusions>
  19. <exclusion>
  20. <groupId>org.springframework.boot</groupId>
  21. <artifactId>spring-boot-starter-web</artifactId>
  22. </exclusion>
  23. </exclusions>
  24. </dependency>
  25. <dependency>
  26. <groupId>org.springframework.cloud</groupId>
  27. <artifactId>spring-cloud-starter-gateway</artifactId>
  28. </dependency>
  29. </dependencies>
  30. <build>
  31. <plugins>
  32. <plugin>
  33. <groupId>org.springframework.boot</groupId>
  34. <artifactId>spring-boot-maven-plugin</artifactId>
  35. </plugin>
  36. </plugins>
  37. </build>
  38. </project>

主启动类

  1. @EnableDiscoveryClient
  2. @SpringBootApplication(exclude = {DataSourceAutoConfiguration.class})
  3. public class MallGatewayApplication {
  4. public static void main(String[] args) {
  5. SpringApplication.run(MallGatewayApplication.class, args);
  6. }
  7. }

配置文件
application.yaml

  1. spring:
  2. application:
  3. name: mall-gateway
  4. cloud:
  5. nacos:
  6. discovery:
  7. server-addr: 192.168.163.131:8848
  8. server:
  9. port: 88

bootstrap.yaml
读取配置中心的配置,在配置中心为每个分组创建各自的命名空间。

  1. spring:
  2. application:
  3. name: mall-gateway
  4. cloud:
  5. nacos:
  6. config:
  7. server-addr: 127.0.0.1:8848
  8. file-extension: yaml
  9. namespace: 07abe11f-3ead-4ae4-add6-71e8f129bfb9

测试:

配置gateway路由规则

  1. spring:
  2. application:
  3. name: mall-gateway
  4. cloud:
  5. nacos:
  6. discovery:
  7. server-addr: 192.168.163.131:8848
  8. gateway:
  9. routes:
  10. #Query A 参数有A就行,Query B,C 参数B的值为C即可
  11. #实现针对于“http://localhost:88/hello?url=baidu”,转发到“https://www.baidu.com/hello”,
  12. #针对于“http://localhost:88/hello?url=qq”的请求,转发到“https://www.qq.com/hello”
  13. - id: baidu_route
  14. uri: https://www.baidu.com
  15. predicates:
  16. - Query=url,baidu
  17. - id: github_route
  18. uri: https://www.github.com
  19. predicates:
  20. - Query=url,github
  21. server:
  22. port: 88

启动项目分别请求:
http://localhost:88/s?wd=Ep%E6%B5%81%E8%8B%8F&url=baidu
https://github.com/zsy0216?url=github
会分别跳转到百度和github 表示成功。