SpringCloud Alibaba

一、简介

Spring Cloud Alibaba 致力于提供分布式应用服务开发的一站式解决方案。此项目包含开发分布式应用服务的必需组件,方便开发者通过 Spring Cloud 编程模型轻松使用这些组件来开发分布式应用服务。

依托 Spring Cloud Alibaba,您只需要添加一些注解和少量配置,就可以将 Spring Cloud 应用接入阿里分布式应用解决方案,通过阿里中间件来迅速搭建分布式应用系统。

GitHub地址:https://github.com/alibaba/spring-cloud-alibaba

二、主要功能

  • 服务限流降级:默认支持 WebServlet、WebFlux, OpenFeign、RestTemplate、Spring Cloud Gateway, Zuul, Dubbo 和 RocketMQ 限流降级功能的接入,可以在运行时通过控制台实时修改限流降级规则,还支持查看限流降级 Metrics 监控。
  • 服务注册与发现:适配 Spring Cloud 服务注册与发现标准,默认集成了 Ribbon 的支持。
  • 分布式配置管理:支持分布式系统中的外部化配置,配置更改时自动刷新。
  • 消息驱动能力:基于 Spring Cloud Stream 为微服务应用构建消息驱动能力。
  • 分布式事务:使用 @GlobalTransactional 注解, 高效并且对业务零侵入地解决分布式事务问题。。
  • 阿里云对象存储:阿里云提供的海量、安全、低成本、高可靠的云存储服务。支持在任何应用、任何时间、任何地点存储和访问任意类型的数据。
  • 分布式任务调度:提供秒级、精准、高可靠、高可用的定时(基于 Cron 表达式)任务调度服务。同时提供分布式的任务执行模型,如网格任务。网格任务支持海量子任务均匀分配到所有 Worker(schedulerx-client)上执行。
  • 阿里云短信服务:覆盖全球的短信服务,友好、高效、智能的互联化通讯能力,帮助企业迅速搭建客户触达通道。

三、组件

**Sentinel**:把流量作为切入点,从流量控制、熔断降级、系统负载保护等多个维度保护服务的稳定性。

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

**RocketMQ**:一款开源的分布式消息系统,基于高可用分布式集群技术,提供低延时的、高可靠的消息发布与订阅服务。

**Dubbo**:Apache Dubbo™ 是一款高性能 Java RPC 框架。

**Seata**:阿里巴巴开源产品,一个易于使用的高性能微服务分布式事务解决方案。

**Alibaba Cloud ACM**:一款在分布式架构环境中对应用配置进行集中管理和推送的应用配置中心产品。

Alibaba Cloud OSS: 阿里云对象存储服务(Object Storage Service,简称 OSS),是阿里云提供的海量、安全、低成本、高可靠的云存储服务。您可以在任何应用、任何时间、任何地点存储和访问任意类型的数据。

Alibaba Cloud SchedulerX: 阿里中间件团队开发的一款分布式任务调度产品,提供秒级、精准、高可靠、高可用的定时(基于 Cron 表达式)任务调度服务。

Alibaba Cloud SMS: 覆盖全球的短信服务,友好、高效、智能的互联化通讯能力,帮助企业迅速搭建客户触达通道。

四、Spring Cloud Alibaba和Spring Cloud 的区别和联系

image-20200531101103114

image-20200531101045571

SpringCloud Alibaba 的优势:

阿里使用过的组件经历了考验,性能强悍,设计合理,搭建简单,学习曲线低

五、最终整合方案

  • SpringCloud Alibaba - Nacos:注册中心(服务发现、注册)

  • SpringCloud Alibaba - Nacos:配置中心(动态配置管理)

  • SpringCloud - Ribbon:负载均衡

  • SpringCloud - Feign:声明式 HTTP 客户端(调用远程服务)

  • SpringCloud Alibaba - Sentinel:服务容错(限流、降级、熔断)

  • SpringCloud - Gateway:API 网关(webflux 编程模式)

  • SpringCloud - Sleuth:调用链监控

  • SpringCloud Alibaba - Seata:分布式事务解决方案

六、版本规范管理

项目的版本号格式为 x.x.x 的形式,其中 x 的数值类型为数字,从 0 开始取值,且不限于 0~9 这个范围。项目处于孵化器阶段时,第一位版本号固定使用 0,即版本号为 0.x.x 的格式。

由于 Spring Boot 1 和 Spring Boot 2 在 Actuator 模块的接口和注解有很大的变更,且 spring-cloud-commons 从 1.x.x 版本升级到 2.0.0 版本也有较大的变更,因此我们采取跟 SpringBoot 版本号一致的版本:

  • 1.5.x 版本适用于 Spring Boot 1.5.x
  • 2.0.x 版本适用于 Spring Boot 2.0.x
  • 2.1.x 版本适用于 Spring Boot 2.1.x
  • 2.2.x 版本适用于 Spring Boot 2.2.x

我们的项目使用的是 Spring Boot 2.2.7,故我们选择 Spring Cloud Alibaba 2.2.x版本

引入依赖:

1
2
3
4
5
6
7
8
9
10
11
<dependencyManagement>
<dependencies>
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-alibaba-dependencies</artifactId>
<version>2.2.0.RELEASE</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>

SpringCloud Alibaba - Nacos

一、作为注册中心

参考官方文档地址:https://github.com/alibaba/spring-cloud-alibaba/blob/master/spring-cloud-alibaba-examples/nacos-example/nacos-discovery-example/readme-zh.md

这里我们以模块 GulimallCouponApplication 为例

  1. 首先,修改 pom.xml 文件,引入 Nacos Discovery Starter。

    1
    2
    3
    4
    <dependency>
    <groupId>com.alibaba.cloud</groupId>
    <artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
    </dependency>
  2. 在应用的 /src/main/resources/application.yml配置文件中配置 Nacos Server 地址及 name

    1
    2
    3
    4
    5
    6
    spring:  
    cloud:
    nacos:
    server-addr: 127.0.0.1:8848
    application:
    name: gulimall-coupon
  3. 使用 @EnableDiscoveryClient 注解开启服务注册与发现功能

    1
    2
    3
    4
    5
    6
    7
    8
    9
    @EnableDiscoveryClient
    @SpringBootApplication
    public class GulimallCouponApplication {

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

    }
  4. 启动 Nacos Server

    1. 直接下载:Nacos Server 下载页
    2. 相对文件夹 nacos/bin,双击打开文件 startup.cmd
  5. 运行 GulimallCouponApplication 测试

    进入 127.0.0.1:8848/nacos ,输入账号密码 nacos(账号密码一样)进入 nacos 的管理系统

    image-20200531112201805

    gulimall-coupon 已经被注册进注册中心,测试成功!

二、作为配置中心

参考官方文档地址:https://github.com/alibaba/spring-cloud-alibaba/blob/master/spring-cloud-alibaba-examples/nacos-example/nacos-config-example/readme-zh.md

  1. 首先,修改 pom.xml 文件,引入 Nacos Config Starter。

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

    如果出现 maven 爆红,请尝试添加版本号或者修改版本号

  2. 在应用的 /src/main/resources 下创建 bootstrap.properties,在配置文件中配置 Nacos Config 元数据

    1
    2
    spring.application.name=gulimall-coupon
    spring.cloud.nacos.config.server-addr=127.0.0.1:8848
  3. 在 nacos 配置中心添加数据集

    image-20200531121805049

    image-20200531121819040

    image-20200531121735368

    注意 Data Id 命名要规范(应用名.properties)

  4. 编写测试类

1
2
3
4
5
6
7
8
9
10
11
12
13
14
/**
* @RefreshScope:动态刷新并获取配置
* @Value("${配置项的名称}"):获取配置
*/

@RefreshScope
class SampleController {

@Value("${user.name}")
String userName;

@Value("${user.age}")
int age;
}
  1. 测试完成!

一些细节

  1. 命名空间:配置隔离

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

    image-20200531150701476

    修改名称空间:

    bootstrap.properties 中添加属性 spring.cloud.config.namespace=命名空间ID

    可以给不同环境设置不同命名空间,也可以给不同微服务设置不同命名空间

  2. 配置集:所有配置的集合

  3. 配置集ID:类似于配置文件名

  4. 配置分组

    默认所有的配置属于:DEFAULT_GROUP

    修改配置分组:

    bootstrap.properties 中添加属性 spring.cloud.config.group=组名

我们的微服务配置:命名空间区分不同微服务,配置分组区分不同开发环境

SpringCloud - OpenFeign

使用 feign 可以实现微服务之间的调用!

我们以 gulimall-member 调用 gulimall-coupon 为例来实现获取会员的优惠价信息功能

  1. 导入依赖

    1
    2
    3
    4
    <dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-openfeign</artifactId>
    </dependency>
  2. 编写测试方法

    com.wxshhh.gulimall.coupon.controller.CouponController:中:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    @RestController
    @RequestMapping("coupon/coupon")
    public class CouponController {
    @Autowired
    private CouponService couponService;

    @RequestMapping("/member/list")
    public R memberCoupons() {
    CouponEntity couponEntity = new CouponEntity();
    couponEntity.setCouponName("满100减10");
    return R.ok().put("coupons", Arrays.asList(couponEntity));
    }

    ……

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

    com.wxshhh.gulimall.member.feign.CouponFeignService 中:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    /**
    * 这是一个声明式的远程调用
    * 括号内的参数是要远程调用的微服务名
    */
    @FeignClient("gulimall-coupon")
    public interface CouponFeignService {

    //直接将需要远程调用的方法的头拷贝过来即可
    @RequestMapping("/coupon/coupon/member/list")
    public R memberCoupons();

    }
  4. 编写测试方法

    com.wxshhh.gulimall.member.controller.MemberController 中:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    @RestController
    @RequestMapping("member/member")
    public class MemberController {
    @Autowired
    private MemberService memberService;

    @Autowired
    CouponFeignService couponFeignService;

    @RequestMapping("/coupons")
    public R test() {
    MemberEntity memberEntity = new MemberEntity();
    memberEntity.setNickname("wxh");
    R memberCoupons = couponFeignService.memberCoupons();
    Object coupons = memberCoupons.get("coupons");
    return R.ok()
    .put("member", memberEntity)
    .put("coupons", coupons);
    }

    ……

    }
  5. 开启远程调用功能,运行微服务 gulimall-member

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    //指定远程调用接口的位置
    @EnableFeignClients(basePackages = "com.wxshhh.gulimall.member.feign")
    @EnableDiscoveryClient
    @SpringBootApplication
    public class GulimallMemberApplication {

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

    }
    image-20200531113732878

    测试成功!

SpringCloud-Gateway

官方文档地址:https://cloud.spring.io/spring-cloud-static/spring-cloud-gateway/2.2.3.RELEASE/reference/html/

概念

  • Route:网关的基本构建基块。它由 ID、目标 URI、Predicate 集合和 Filter 集合定义。如果聚合 Predicate 为 true,则匹配路由。
  • Predicate: 这是Java 8 函数断言。输入类型是弹簧框架服务器WebExchange。这允许您匹配 HTTP 请求的任何内容,如标头或参数。
  • Filter:这些是使用特定工厂构造的弹簧框架网关Filter的实例。在这里,您可以在发送下游请求之前或之后修改请求和响应。

工作原理

image-20200601101342702

Clients make requests to Spring Cloud Gateway. If the Gateway Handler Mapping determines that a request matches a route, it is sent to the Gateway Web Handler. This handler runs the request through a filter chain that is specific to the request. The reason the filters are divided by the dotted line is that filters can run logic both before and after the proxy request is sent. All “pre” filter logic is executed. Then the proxy request is made. After the proxy request is made, the “post” filter logic is run.

配置样例

1
2
3
4
5
6
7
8
9
10
11
12
13
spring:
cloud:
gateway:
routes:
- id: baidu_route
uri: https://www.baidu.com
predicates:
- Query=url,baidu

- id: qq_route
uri: https://www.qq.com
predicates:
- Query=url,qq