Kaze
Kaze
Published on 2022-05-26 / 220 Visits
0
0

SpringCloud

服务端

包版本管理

一个项目运行时,同一个依赖包只能使用一个版本,所以要对子项目中相同的依赖进行统一版本管理。

一般步骤如下:

1.修改根pom

在根pom.xml中引入<dependencyManagement>标签,用于管理依赖包的版本号。

dependencyManagement 标签中声明所依赖的 jar 包的版本号等信息,那么所有子项目再次引入此依赖 jar 包时则无需显式的列出版本号。

<dependencyManagement>
    <dependencies>
        <dependency>
            <groupId></groupId>
            <artifactId></artifactId>
            <version></version>
        </dependency>
    </dependencies>
</dependencyManagement>

<dependencies><dependencyManagement> 标签是并列的,<dependencies>用于引入依赖,dependencyManagement 仅仅用于管理依赖包的版本号。

2.删除子项目pom中的依赖的版本号声明

集成Spring Cloud Alibaba

1.添加一个版本号变量

根pom.xml增加 一个 spring-cloud-alibaba.version 变量定义

<properties>
       <!--SpringCloud Alibaba版本-->
       <spring-cloud-alibaba.version>2.2.6.RELEASE</spring-cloud-alibaba.version>
</properties>

有时候同一系列(groupId相同)的多个依赖包往往使用同一个版本号,可以用一个变量进行版本号管理。

2.根pom增加依赖管理

<dependencyManagement>
    <dependencies>
        <dependency>
            <groupId>com.alibaba.cloud</groupId>
            <artifactId>spring-cloud-alibaba-dependencies</artifactId>
            <version>${spring-cloud-alibaba.version}</version>
            <type>pom</type>
            <scope>import</scope>
        </dependency>
    </dependencies>
</dependencyManagement>

<type>pom</type><scope>import</scope> 组合起来,表示从 spring-cloud-alibaba-dependencies 的 pom 文件中获取到配置的多个依赖包

3.子项目依赖

修改 application/pom.xml 文件, 添加 两个依赖

<dependencies>
        <!-- Spring Cloud Begin -->
        <dependency>
            <groupId>com.alibaba.cloud</groupId>
            <artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
        </dependency>
        <dependency>
            <groupId>com.alibaba.cloud</groupId>
            <artifactId>spring-cloud-starter-alibaba-nacos-config</artifactId>
        </dependency>
        <!-- Spring Cloud End -->
</dependencies>

4.添加注解

修改主启动类:Application ,添加一个注解 @EnableDiscoveryClient

@EnableDiscoveryClientSpring Cloud Alibaba 的原生注解,表示开启服务注册发现功能,服务提供者和消费者都要使用此注解。

5.配置 nacos

application.properties中添加配置项

#application name
spring.application.name=xxxx-user-app
#Nacos Server ip and port
spring.cloud.nacos.discovery.server-addr=nacos.dev.youkeda.com:8848

Dubbo RPC-提供用户服务

内部系统之间的通讯、调用,用 Dubbo RPC 效率更高。

使用 Dubbo 的 RPC 方式调用服务

1.增加配置

修改application.properties配置文件

#application name
spring.application.name=xxxx-user-app
#Nacos Server ip and port
spring.cloud.nacos.discovery.server-addr=nacos.dev.youkeda.com:8848

## mount to Spring Cloud
dubbo.registry.address = spring-cloud://localhost
## auto scan
dubbo.scan.base-packages = com.youkeda.comment.service.impl
dubbo.protocol.name = dubbo
dubbo.protocol.port = -1

spring-cloud://localhost 表示Dubbo 注册中心挂载到 Spring Cloud 上,也就是说,使用与 Spring Cloud 相同的配置,并且设置通信协议为 dubbo 。

dubbo.protocol.port 用于设置 Dubbo 端口号,值为 -1 表示系统自动扫描可用的端口(从20880开始递增)。

2.子项目引入依赖包

引入 Dubbo 相关的包:

<dependency>
      <groupId>com.alibaba.cloud</groupId>
      <artifactId>spring-cloud-starter-dubbo</artifactId>
</dependency>

3.注册服务

在服务实现类上加上注解@DubboService,无需指定版本号。

Dubbo RPC-调用用户服务

1.引入 Spring Cloud Alibaba

同上

2.子项目引入依赖

服务实现类引入依赖包:

<!--dubbo-->
<dependency>
        <groupId>com.alibaba.cloud</groupId>
        <artifactId>spring-cloud-starter-dubbo</artifactId>
</dependency>

3.加注解

CommentServiceImpl 的属性 userService 上加上注解 @DubboReference() ,系统会自动注入一个实例

4.增加配置

修改项目配置文件application.properties

#application name
spring.application.name = xxxx-comment-app
#Nacos Server ip and port
spring.cloud.nacos.discovery.server-addr = nacos.dev.youkeda.com:8848

## mount to Spring Cloud
dubbo.registry.address = spring-cloud://localhost
## auto scan
dubbo.scan.base-packages = com.youkeda.comment.service.impl
dubbo.protocol.name = dubbo
dubbo.protocol.port = -1
## 多个服务用逗号隔开
dubbo.cloud.subscribed-services = xxxx-user-app

dubbo.cloud.subscribed-services 用于设置服务提供方的应用名称,正因为有了这个配置项,所以服务提供者和消费者都不用指定版本号了

Feign调用

Feign-客户端

1.管理新依赖的版本

根pom.xml增加 一个 spring-cloud.version 变量定义

<spring-cloud.version>Hoxton.SR6</spring-cloud.version>

根pom 的依赖包管理中,加入对 SpringCloud 的依赖:

<dependencyManagement>
    <dependencies>
        <dependency>
                <groupId>org.springframework.cloud</groupId>
                <artifactId>spring-cloud-dependencies</artifactId>
                <version>${spring-cloud.version}</version>
                <type>pom</type>
                <scope>import</scope>
        </dependency>
	</dependencies>
</dependencyManagement>

2.开启 Feign 客户端

主启动类 Application 上加一个注解:

@EnableFeignClients(basePackages = "com.youkeda.comment")

@EnableFeignClients 表示开启 Feign 客户端,同时,自动扫描指定的包,系统会自动实现客户端。

3.子项目引入依赖

子项目 comment.service 的 pom.xml 文件中,加一个依赖项:

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

4.增加具体的客户端接口

在子项目 comment.service 中写一个

@FeignClient(name = "xxxx-user-app")
public interface UserFeign {

    @GetMapping("/user/findByIds")
    public List<User> findByIds(@RequestParam("ids") List<Long> ids);
}

UserFeign 接口相当于一个远程 API 的代理。@FeignClient 注解主要用于配置远程服务的名称,表示将使用那个远程服务的 API。

接口中定义的方法必须要与远程服务的API一致。

UserFeign.findByIds() 方法被调用时,其实是向用户系统发出 /user/findByIds的http 请求,同时附带上方法参数值。

	@Autowired
    private UserFeign userFeign;

	List<User> userModels = userFeign.findByIds(userIds);

UserFeign 虽然是一个接口,但系统会自动构建一个代理对象实例注入。

总结

构建分布式应用的大概步骤:

  1. 项目模块化划分
  2. 依赖包版本管理
  3. 引入依赖包
  4. 完善配置(包括各种名称、地址、端口等)
  5. 使用注解
  6. 完成具体业务逻辑

Sentinel服务治理

Sentinel 控制台

Sentinel 是 SpringCloudAlibaba 的一个重要组件,提供了流量控制、熔断降级、系统负载保护等多个维度来保障服务之间的稳定性。

点此下载Sentinel的jar包,利用终端命令启动Sentinel控制台

java -Dserver.port=9000 -Dcsp.sentinel.dashboard.server=localhost:9000 -Dproject.name=sentinel-dashboard -jar sentinel-dashboard-1.8.2.jar

默认账号密码均为sentinel

dubbo 调用-整合 Sentinel

无论是服务提供者,还是服务消费者,都需要接入到 Sentinel ,才能在 Sentinel控制台 上看到相关的数据。

1.application/pom.xml 加入依赖

 <!--SpringCloud ailibaba sentinel -->
        <dependency>
            <groupId>com.alibaba.cloud</groupId>
            <artifactId>spring-cloud-starter-alibaba-sentinel</artifactId>
        </dependency>
        <dependency>
            <groupId>com.alibaba.csp</groupId>
            <artifactId>sentinel-apache-dubbo-adapter</artifactId>
        </dependency>

2.新增配置项

application.properties 文件新增配置项:

spring.cloud.sentinel.transport.dashboard = localhost:9000

Feign 调用-整合 Sentinel

1.application/pom.xml 加入依赖

 <!--SpringCloud ailibaba sentinel -->
        <dependency>
            <groupId>com.alibaba.cloud</groupId>
            <artifactId>spring-cloud-starter-alibaba-sentinel</artifactId>
        </dependency>

2.新增配置项

spring.cloud.sentinel.transport.dashboard = localhost:9000

feign.sentinel.enabled = true

流量控制

配置流控规则

img

熔断

一个分布式架构的系统,服务的稳定性,除了受到外部流量的影响外,还可能受到下级服务的影响。

当下级服务出现问题时,熔断可以及时停止调用这个服务,防止出现问题。

Sentinel 提供以下几种熔断策略:

  • 慢调用比例 (SLOW_REQUEST_RATIO):选择以慢调用比例作为阈值,需要设置允许的慢调用 RT(即最大的响应时间),请求的响应时间大于该值则统计为慢调用。当单位统计时长(statIntervalMs)内请求数目大于设置的最小请求数目,并且慢调用的比例大于阈值,则接下来的熔断时长内请求会自动被熔断。经过熔断时长后熔断器会进入探测恢复状态(HALF-OPEN 状态),若接下来的一个请求响应时间小于设置的慢调用 RT 则结束熔断,若大于设置的慢调用 RT 则会再次被熔断。

  • 异常比例 (ERROR_RATIO):当单位统计时长(statIntervalMs)内请求数目大于设置的最小请求数目,并且异常的比例大于阈值,则接下来的熔断时长内请求会自动被熔断。经过熔断时长后熔断器会进入探测恢复状态(HALF-OPEN 状态),若接下来的一个请求成功完成(没有错误)则结束熔断,否则会再次被熔断。异常比率的阈值范围是 [0.0, 1.0],代表 0% - 100%。

  • 异常数 (ERROR_COUNT):当单位统计时长内的异常数目超过阈值之后会自动进行熔断。经过熔断时长后熔断器会进入探测恢复状态(HALF-OPEN 状态),若接下来的一个请求成功完成(没有错误)则结束熔断,否则会再次被熔断。

熔断器可以在检测到下游服务出错时,不再执行调用,而是及时返回,保护上游服务和应用。

降级

为了改善熔断后带来的影响,可以做一些优化、补偿,这个熔断后的处理,叫作服务降级。

例如,如果某电商网站的商品服务挂了,那么系统熔断后,页面上看不到任何商品,这样体验很不好。这时如果能展示一些预置好的商品,起码页面上有充实的内容,体验得到改善。

除了触发熔断规则引发服务方法调用降级以外, Sentinel 还支持服务方法调用抛异常时自动降级,回调另一个方法。

一、代码改造:

//原方法
public List<User> findByIds(@Param("ids") List<Long> ids);
//原方法的熔断 降级处理方法
public List<User> findByIdsHandler(List<Long> ids, BlockException ex);
//原方法的异常 降级处理方法
public List<User> testFallback(List<Long> ids, Throwable e);

修改服务实现类代码

原方法实现加一个注解:

@SentinelResource(value = "findUserByIds",
                  blockHandler = "findByIdsHandler",
                  blockHandlerClass = UserBlockHandler.class,
                  fallback = "testFallback",
        		  fallbackClass = TestController.class)
public List<User> findByIds(@Param("ids") List<Long> ids) {

}

@SentinelResource 注解就是表示此方法需要做降级处理。

value 表示待处理的资源的名称

blockHandler 表示指定一个熔断后做降级处理的方法名。

blockHandlerClass 指定熔断降级处理方法所在的类。

fallback 指定回调方法名。

fallbackClass 指定回调方法所在的类。

二、配置熔断规则:

按照代码中 @SentinelResource 注解的 value 值配置熔断规则

Nacos动态配置

安装nacos

点此下载稳定版

unzip nacos-server-2.0.3.zip
cd nacos
sh startup.sh -m standalone

浏览器输入http://IP地址:8848访问

动态配置

修改配置后立即生效就叫做动态配置,Nacos 除了作为注册中心以外,还可以作为配置中心,提供动态配置的功能。

1.新增配置文件

application/src/main/resources/ 目录下,新建一个 bootstrap.properties 文件。

bootstrap.properties的优先级比application.properties高,系统会先从 bootstrap.properties 文件中读取 Nacos 动态配置服务器的地址。

Bootstrap配置具有较高的优先级,不会被application.properties中相同的配置项覆盖。

Bootstrap属于引导配置,Application属于应用配置。

2.配置内容

在bootstrap.properties 文件中,写入应用名称Nacos动态配置服务器地址这两个配置项:

#application name
spring.application.name = feidian-user

#Nacos Server ip and port
spring.cloud.nacos.config.server-addr = nacos.dev.youkeda.com:8848

application.properties 文件中的 spring.application.name 配置项可以删除掉。

3.代码改造
在实现类中加一个注解:

@DubboService
@RefreshScope
public class UserServiceImpl implements UserService{
    @Value("${code.600.message}")
	private String message600;
}

@RefreshScope的作用就是 类中的属性对 Nacos 配置进行监听,一旦 Nacos 重新发布新的属性值则替换原来的值,实现刷新。

4.管理配置项

动态配置的配置项是写在 Nacos 中的,项目从 Nacos 读取配置项的值,注入到变量中。

img

Data ID 值的格式是 应用名.properties

定制Springboot starter

什么是starter

Springboot 之所以简化了应用的开发和部署,起到重要作用的就是 starter 。

starter 也叫启动器,只需要在 Maven 中引入 starter 依赖,SpringBoot 就能自动扫描到要加载的信息并启动相应的默认配置。

独立于业务代码之外的功能配置模块可以封装成starter,复用的时候只需要将其在 pom 中引用依赖即可,SpringBoot 会为我们自动完成装配。

starter 项目相当于一个模块,跟应用项目的明显区别是,不需要Application 启动类,starter 应该是被其它应用依赖的。

新建 starter 项目

1.创建配置项类

新建一个 config 包,用于放配置相关的类

@ConfigurationProperties(prefix = "user.code")
public class UserProperties {

    private String message600;

    private String message601;

    private String message602;
}

@ConfigurationProperties(prefix = "user.code") 用于为配置项指定一个前缀

在nacos中增加配置(动态配置)or 在 application.properties 中增加配置(静态配置)

在 Nacos 上进行动态配置,优点是修改方便,但缺点是所有集成了 starter 的应用,都需要配置一次

user.code.message600=用户名不能为空
user.code.message601=密码不能为空
user.code.message602=用户名已经存在,无法注册
user.code.enabled=true

user.code.message600 配置项会自动映射到属性 message600

2.配置项控制类

配置项控制类用于控制配置项是否生效

//标记为配置类
@Configuration
//启动配置属性
@EnableConfigurationProperties(UserProperties.class)
// 如果设置了 user.code.enabled=false 则配置不生效,默认只有值为 false 的时候才不生效。其它任意字符,都会让配置生效。
// 如果没有设置 user.code.enabled 则默认配置生效(matchIfMissing = true)
@ConditionalOnProperty(prefix = "user.code", value = "enabled", matchIfMissing = true)
public class UserConfig {

    @Autowired
    private UserProperties userProperties;

    @Autowired
    private UserService userService;

    @PostConstruct
    public void init() {
        System.out.println("UserConfig init successful.");

        if (userProperties != null) {
            System.out.println("user.code.message600" + userProperties.getMessage600());
            userService.setUserProperties(userProperties);
        }
    }
}

配置生效的时候,系统会自动实例化 userProperties 并读取配置映射到属性中;init() 方法也会执行。反之,不生效,则 userProperties 不实例化,值为 null;init() 方法也不会执行。

3.服务接口和实现类提供配置方法

接口 增加 一个 setter 方法:

public interface UserService {
  void setUserProperties(UserProperties userProperties);
}

实现类 增加 配置项类依赖:

@Service
public class UserServiceImpl implements UserService {

    private UserProperties userProperties;

    public void setUserProperties(UserProperties userProperties) {
        this.userProperties = userProperties;
    }
}

UserProperties userProperties 属性没有加 @Autowired 注解让系统自动注入,就是为了在 UserConfig 中控制是否注入实例。

4.系统配置文件

resources 目录下, 新建一个 META-INF (全大写字母)目录,然后在此新目录下再建一个 spring.factories 文件,文件内容为:

org.springframework.boot.autoconfigure.EnableAutoConfiguration=com.youkeda.comment.config.UserConfig

只需要指定配置项控制类即可。

5.starter 项目发布

进入项目目录,输入命令mvn clean install,这个命令会把 starter 项目安装到本地电脑的 maven 仓库中。

本地电脑的 maven 仓库一般在用户根目录下 ~/.m2/repository


Comment