分布式组件

SpringCloud Alibaba

image-20230518131247334

结合SpringCloud Alibaba 我们最终的技术搭配方案为:

  • SpringCloud Alibaba - Nacos:注册中心
  • SpringCloud Aibaba - Nacos:配置中心
  • SpringCloud - Ribbon:负载均衡
  • SpringCloud - Feign:声明式HTTP客户端(调用远程服务)
  • SpringCloud Alibaba - Sentinel:服务容错(限流,降级,熔断)
  • SpringCloud - Gateway :API网关
  • SpringCloud - Sleuth:调用链监控
  • SpringCloud Alibaba - Seata:分布式事务解决方案s

找到对应的SpringBoot,SpringCloud和SpringCloud Alibaba对应的版本号,引入依赖到common模块中

1
2
3
4
5
6
7
8
9
10
11
12
13
在common的pom.xml中加入
# 下面是依赖管理,相当于以后再dependencies里引spring cloud alibaba就不用写版本号, 全用dependencyManagement进行管理
<dependencyManagement>
<dependencies>
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-alibaba-dependencies</artifactId>
<version>2.1.0.RELEASE</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>

SpringCloud Alibaba中的组件

(1)Nacos注册中心

一个更易于构建云原生应用的动态服务发现、配置管理和服务管理平台。

作为我们的注册中心和配置中心。

步骤根据官方文档:https://github.com/alibaba/spring-cloud-alibaba/blob/2022.x/spring-cloud-alibaba-examples/nacos-example/nacos-discovery-example/readme-zh.md

1
2
3
4
5
6
7
先了解一下 Spring Cloud 应用如何接入 Nacos Discovery。
1 首先,修改 common中的pom.xml 文件,引入 Nacos Discovery Starter。
作用:将我们的服务注册到注册中心中,并且能够发现注册中心中的服务
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
</dependency>

下载nacos,下载版本为1.1.3.

解压下载完成后的nacos,点击里面的startup.cmd,开启nacos。可以看见地址为:

image-20230518172255501

开启nacos~

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
2 在应用的每个服务中的application.yml 配置文件中配置 Nacos Server 地址和微服务名称
server:
port: 7000

spring:
datasource:
username: root
password: Zlw199805
url: jdbc:mysql://192.168.106.100:3306/gulimall_sms?useUnicode=true&characterEncoding=UTF-8&useSSL=false&serverTimezone=Asia/Shanghai
driver-class-name: com.mysql.cj.jdbc.Driver
cloud:
nacos:
discovery:
server-addr: 127.0.0.1:8848
application:
name: gulimall-coupon

mybatis-plus:
mapper-locations: classpath:/mapper/**/*.xml
global-config:
db-config:
id-type: auto
3 我们要配置nacos服务器的地址,也就是注册中心地址,但是我们还没
有nacos服务器,所以我们需要启动nacos server创建nacos服务
器(软件官方可以下载)
启动命令windows:startup.cmd -m standalone

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22

4 使用 @EnableDiscoveryClient 注解开启服务注册与发现功能
package com.zlw.gulimall.coupon;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;


@EnableDiscoveryClient
@SpringBootApplication
public class GulimallCouponApplication {

public static void main(String[] args) {
SpringApplication.run(GulimallCouponApplication.class, args);
}

}


5 访问http://127.0.0.1:8848/nacos/ 账号密码nacos
出现如下页面,则表示访问成功

image-20230518173136774

按照以上步骤,注册member

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
server:
port: 8000


spring:
datasource:
username: root
password: Zlw199805
url: jdbc:mysql://192.168.106.100:3306/gulimall_ums?useUnicode=true&characterEncoding=UTF-8&useSSL=false&serverTimezone=Asia/Shanghai
driver-class-name: com.mysql.cj.jdbc.Driver
cloud:
nacos:
discovery:
server-addr: 127.0.0.1:8848
application:
name: gulimall-member

mybatis-plus:
mapper-locations: classpath:/mapper/**/*.xml
global-config:
db-config:
id-type: auto

在启动类上加注解:
package com.zlw.gulimall.member;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;

@EnableDiscoveryClient
@SpringBootApplication
public class GulimallMemberApplication {

public static void main(String[] args) {
SpringApplication.run(GulimallMemberApplication.class, args);
}

}

出现下图,成功!

(2)Nacos注册中心-远程调用别的服务

某个服务想要远程调用别的服务时的操作步骤:

  • 引入 open-feign依赖

  • 编写一个接口,告诉SpringCloud这个接口需要调用远程服务

    • 声明接口的每一个方法,方法都是调用远程服务的那个请求
  • 开启远程调用功能:@EnableFeignClients(basePackages = "com.zlw.gulimall.member.feign")

编写会员想要访问,会员的优惠票(会员服务访问优惠券服务)

(1)第一步:在会员服务中引入依赖:

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

(2)在coupon中新增如下测试方法:用于返回会员的优惠券

1
2
3
4
5
6
7
@RequestMapping("/member/coupon")
public R memberCoupon(){
// 应该去数据库查用户对于的优惠券,但这个我们简化了,不去数据库查了,构造了一个优惠券给他返回
CouponEntity couponEntity = new CouponEntity();
couponEntity.setCouponName("满100减10");
return R.ok().put("coupon",couponEntity);
}

(3)在member中新增如下测试方法,用于获取会员的优惠券

1
2
3
4
5
6
7
8
9
10
11
@Autowired
private CouponService couponService;

@RequestMapping("/coupon")
public R test(){
MemberEntity memberEntity = new MemberEntity();
memberEntity.setNickname("张三");
R r = couponService.memberCoupon();//假设张三去数据库查了后返回了张三的优惠券信息
// 打印会员和优惠券信息
return R.ok().put("member",memberEntity).put("coupon",r.get("coupon"));
}

(4)编写一个接口,告诉SpringCloud这个接口需要调用远程服务:

1
2
3
4
5
6
7
8
9
10
11
12
package com.zlw.gulimall.member.feign;

import com.zlw.common.utils.R;
import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.web.bind.annotation.RequestMapping;

@FeignClient("gulimall-coupon")//告诉spring cloud这个接口是一个远程客户端,要调用coupon服务,再去调用coupon服务/coupon/coupon/member/coupon对应的方法
public interface CouponService {
@RequestMapping("/coupon/coupon/member/coupon")
public R memberCoupon();
}

(5)开启远程调用功能

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
package com.zlw.gulimall.member;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
import org.springframework.cloud.openfeign.EnableFeignClients;

@EnableFeignClients(basePackages = "com.zlw.gulimall.member.feign")//告诉spring这里面是一个远程调用客户端,member要调用的接口
@EnableDiscoveryClient
@SpringBootApplication
public class GulimallMemberApplication {

public static void main(String[] args) {
SpringApplication.run(GulimallMemberApplication.class, args);
}

}

测试成功~

image-20230520123502640

(3)Nacos作为配置中心

步骤根据官方文档:https://github.com/alibaba/spring-cloud-alibaba/blob/2022.x/spring-cloud-alibaba-examples/nacos-example/nacos-config-example/readme-zh.md

我们还可以用nacos作为配置中心。配置中心的意思是不在application.properties 等文件中配置了,而是放到nacos配置中心公用,这样无需每台机器都改。

将coupon服务中的配置通过nacos配置中心管理的步骤:

  • 引入配置中心依赖,放到common中

    1
    2
    3
    4
    <dependency>
    <groupId>com.alibaba.cloud</groupId>
    <artifactId>spring-cloud-starter-alibaba-nacos-config</artifactId>
    </dependency>
  • 在coupons项目中创建/src/main/resources/bootstrap.properties ,这个文件是 springboot里规定的,他优先级别application.properties

1
2
spring.application.name=gulimall-coupon
spring.cloud.nacos.config.server-addr=192.168.11.1:8848
  • 举例测试

    1
    2
    3
    4
    5
    6
    7
    8
    9
    @Value("${coupon.user.name}")
    private String name;
    @Value("${coupon.user.age}")
    private Integer age;

    @RequestMapping("/test")
    public R test(){
    return R.ok().put("name",name).put("age",age);
    }
  • 浏览器去nacos里的配置列表,点击+号,data ID:gulimall-coupon.properties,配置 # gulimall-coupon.properties

    image-20230520131619533

  • 然后点击发布。重启coupon,访问:http://localhost:7000/coupon/coupon/test

image-20230520131729368

  • 给couponController加上@RefreshScope注解,可以通过修改nacos配置中心的配置,不用重新启动,就会修改。

    image-20230520131937958

  • 重启后,在nacos浏览器里修改配置,修改就可以观察到能动态修改了 nacos的配置内容优先于项目本地的配置内容。

(4)Nacos作为配置中心的一些细节

(1)命名空间:配置隔离

默认:public(保留空间),默认新增的所有配置都在public空间。

  • 可以根据开发环境来隔离(开发、测试、生产)。

    注意:在bootstrap.properties配置上,需要指定使用哪个命名空间下的配置:spring.cloud.nacos.config.namespace

  • 根据微服务之间隔离,每个微服务都创建自己的命名空间,只加载自己命名空间下的所有配置。

(2)配置集:所有配置的集合

(3)配置集ID:类似文件名(Data ID)

(4)配置分组:默认所有的配置集都属于:DEFAULT_GROUP。

本项目中:每个微服务创建自己的命名空间,使用配置分组区分环境,dev、test、prod

image-20230520145052069

image-20230520145356403

(5)同时加载多个配置集

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
#我们可以把原来application.yml里的内容都分文件抽离出去。我们在nacos里创建好后,在coupons里指定要导入的配置即可。

bootstrap.properties
spring.application.name=gulimall-coupon
spring.cloud.nacos.config.server-addr=127.0.0.1:8848


spring.cloud.nacos.config.namespace=ed042b3b-b7f3-4734-bdcb-0c516cb357d7 # # 可以选择对应的命名空间 ,即写上对应环境的命名空间ID
spring.cloud.nacos.config.group=dev # 配置文件所在的组

spring.cloud.nacos.config.ext-config[0].data-id=datasource.yml
spring.cloud.nacos.config.ext-config[0].group=dev
spring.cloud.nacos.config.ext-config[0].refresh=true

spring.cloud.nacos.config.ext-config[1].data-id=mybatis.yml
spring.cloud.nacos.config.ext-config[1].group=dev
spring.cloud.nacos.config.ext-config[1].refresh=true

spring.cloud.nacos.config.ext-config[2].data-id=other.yml
spring.cloud.nacos.config.ext-config[2].group=dev
spring.cloud.nacos.config.ext-config[2].refresh=true

Nacos中datasource.yml内容为:

1
2
3
4
5
6
spring:
datasource:
username: root
password: Zlw199805
url: jdbc:mysql://192.168.106.100:3306/gulimall_sms?useUnicode=true&characterEncoding=UTF-8&useSSL=false&serverTimezone=Asia/Shanghai
driver-class-name: com.mysql.cj.jdbc.Driver

Nacos中mabatis.yml内容为:

1
2
3
4
5
mybatis-plus:
mapper-locations: classpath:/mapper/**/*.xml
global-config:
db-config:
id-type: auto

其他的配置为

1
2
3
4
5
6
7
8
9
10
11
other.yml
server:
port: 7000

spring:
cloud:
nacos:
discovery:
server-addr: 127.0.0.1:8848
application:
name: gulimall-coupon

更多的功能可以参考Nacos官网:https://nacos.io/zh-cn/docs/v2/quickstart/quick-start.html

(6)API网关(SpringCloud GateWay)

发送请求需要知道商品服务的地址,如果商品服务器有100服务器,1号掉线后,还得改,所以需要网关动态地管理,他能从注册中心中实时地感知某个服务上线还是下线。

请求也要加上询问权限,看用户有没有权限访问这个请求,也需要网关。

所以我们使用spring cloud的gateway组件做网关功能。

**三大核心概念: **

  • Route:发一个请求给网关,网关要将请求路由到指定的服务。路由有id,目的地uri,断言的集合,匹配了断言就能到达指定位置,
  • Predicate:就是java里的断言函数,匹配请求里的任何信息,包括请求头等
  • Filter:过滤器请求和响应都可以被修改。

客户端发请求给服务端。中间有网关。先交给映射器,如果能处理就交给handler 处理,然后交给一系列filer,然后给指定的服务,再返回回来给客户端。

在这里插入图片描述

总结:当我们请求到达网关,网关利用断言来判断这次的请求是否符合某个路由规则,如果符合,就按照路由规则路由到指定地方,而要去这这些指定地方,就要经过一系列的filter过滤

(7)创建测试API网关

创建gulimall-gateway模块

在pom中引入common依赖

版本环境保持一致

1
2
3
4
5
6
7
8
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.1.8.RELEASE</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>

<spring-cloud.version>Greenwich.SR3</spring-cloud.version>

开启注册服务发现@EnableDiscoveryClient:网关想要路由到其他服务,就知道其他服务在哪了

首先要启动nacos

image-20230522193946848

在application.propertise中配置nacos的注册中心地址和应用名字

1
2
3
spring.cloud.nacos.discovery.server-addr=127.0.0.1:8848
spring.application.name=gulimall-gateway
server.port=88

同时也将网关的配置交给nacos配置中心来管理,则编写配置中心的配置文件(bootstrap.propertise)

1
2
3
spring.cloud.nacos.config.server-addr=127.0.0.1:8848
spring.cloud.nacos.config.namespace=8b0d5f8f-186b-4529-9677-34fda1735736
spring.application.name=gulimall-gateway

在nacos中创建gateway命名空间

image-20230522194924062

这时启动gateway模块时,发生以下错误:

image-20230522195655025

原因:
在pom中引入了mybatis-spring-boot-starter 坐标,Spring boot默认会加载org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration类,DataSourceAutoConfiguration类使用了@Configuration注解向spring注入了dataSource bean。因为工程中没有关于dataSource相关的配置信息,当spring创建dataSource bean因缺少相关的信息就会报错

解决方案:

方案一:去掉 mybatis 的坐标依赖
方案二:将启动类上的注解改为 @SpringBootApplication(exclude = DataSourceAutoConfiguration.class)
方案三:在 application.yml 配置上数据库的连接信息
这里使用方案二

1
@SpringBootApplication(exclude = {DataSourceAutoConfiguration.class})//排除和数据源有关的配置

网关想要做的事情就是将请求转给其他服务

1
2
3
测试一:localhost:88?url=baidu # 跳到百度页面 

测试二:localhost:88?url=qq # 跳到qq页面

将配置写到yml中

参考:https://docs.spring.io/spring-cloud-gateway/docs/current/reference/html/

application.yml如下:

1
2
3
4
5
6
7
8
9
10
11
12
spring:
cloud:
gateway:
routes:
- id: baidu_route
uri: http://www.baidu.com
predicates:
- Query=url,baidu #有url=baidu时跳转到http://www.baidu.com
- id: qq-route
uri: http://qq.com
predicates:
- Query=url,qq #有url=qq时跳转到http://qq.com

成功L~

image-20230522200942890

image-20230522201131434


分布式组件
http://example.com/2023/05/18/分布式组件/
作者
zlw
发布于
2023年5月18日
许可协议