Spring Cloud Alibaba 致力于提供微服务开发的一站式解决方案。此项目包含开发分布式应用微服务的必需组件,方便开发者通过 Spring Cloud 编程模型轻松使用这些组件来开发分布式应用服务。
依托 Spring Cloud Alibaba,只需要添加一些注解和少量配置,就可以将 Spring Cloud 应用接入阿里微服务解决方案,通过阿里中间件来迅速搭建分布式应用系统。

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

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

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

如何使用

引入依赖

electricity-common模块引入依赖。

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

版本管理规范

项目的版本号格式为 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 版本也有较大的变更,因此springcloud alibaba采取跟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
  • 2021.x 版本适用于 Spring Boot 2.4.x

Nacos Discovery

接入 Nacos Discovery

  • electricity-common模块的 pom.xml 文件中引入Nacos Discovery Starter
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
</dependency>
  • electricity-coupon模块的application.yml文件中添加 nacos 的服务地址和应用名称
spring:
cloud:
nacos:
discovery:
server-addr: 127.0.0.1:8848
application:
name: electricity-coupon
  • 在启动类上加入@EnableDiscoveryClient注解开启服务注册与发现功能
@SpringBootApplication
@EnableDiscoveryClient // 开启nacos服务注册与发现功能
public class ElectricityCouponApplication {

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

启动 Nacos Server

  • 下载 Nacos Server

在 github 上下载 Nacos Server

  • 启动 Nacos Server

将下载好的压缩包解压出来,修改 bin 目录下的start.cmd文件。nacos server 配置的默认是集群启动,本机电脑上我们以单机的方式启动,所以要修改为单机模式。

# 将 cluster修改为 standalone
set MODE="standalone"

双击start.cmd文件,启动 nacos server。

linux/mac 等类 unix 系统,启动start.sh文件。

sh startup.sh -m standalone
  • 启动电商项目

启动刚才配置 nacos 的electricity-coupon模块。

验证

在浏览器输入http://127.0.0.1:8848/nacos,输入用户名和密码(都是nacos)进入控制台,可以看到已经注册的服务。

配置多个服务实例时,都是按照上面的步骤进行配置。

Feign

Feign 是一个声明式的 HTTP 客户端,他的目的就是让远程调用更加简单。给远程服务发的是 HTTP 请求。

这里测试会员服务远程调用优惠券服务。

引入 maven 依赖

openfeign 的依赖在创建项目时已经导入,如果没有引入,在各个微服务模块中都需要导入。

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

生成优惠券

electricity-coupon模块模拟优惠券,供会员模块调用。

@RestController
@RequestMapping("coupon/coupon")
public class CouponController {
@Autowired
private CouponService couponService;

/**
* 模拟优惠券
* @return 优惠券
*/
@RequestMapping("/member/list")
public R memberCoupon() {
// 模拟优惠券
CouponEntity coupon = new CouponEntity();
coupon.setCouponName("满199减100");
return R.ok().put("coupons", Arrays.asList(coupon));
}
}

创建远程调用客户端接口

远程调用客户端告诉 springCloud 将要调用 coupon 服务的各种模块。

@FeignClient("electricity-coupon") // 告诉 SpringCloud 这是一个远程客户端,调用 coupon 服务
public interface CouponFeignService {
// 这里是直接复制优惠券服务中定义的方法签名
// 会员优惠券服务
@RequestMapping("/coupon/coupon/member/list")
public R memberCoupon();
}

开启远程调用服务

在会员服务启动类上卡其远程调用服务。

@SpringBootApplication
@EnableDiscoveryClient
@EnableFeignClients(basePackages = "com.laughing.electricity.member.feign") // 开启远程调用服务
public class ElectricityMemberApplication {

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

测试远程调用

@RestController
@RequestMapping("member/member")
public class MemberController {
@Autowired
CouponFeignService couponFeignService;

@RequestMapping("/coupons")
public R test() {
MemberEntity memberEntity = new MemberEntity();
memberEntity.setNickname("杰哥不要啊");
R memberCoupon = couponFeignService.memberCoupon();
// memberCoupon.get("coupons") 这里的 coupons 是 memberCoupon 返回的 coupons,要对应
return R.ok().put("member", memberEntity).put("coupons", memberCoupon.get("coupons"));
}
}

如果你配置的 springboot 和 springcloud 版本比较高,启动项目时会报下面的错误。
No Feign Client for loadBalancing defined. Did you forget to include spring-cloud-starter-loadbalancer?

解决方案:将electricity-common模块中的 springcloud 依赖修改一下。

<!--SpringCloud Feign在Hoxton.M2 RELEASED版本之后不再使用Ribbon而是使用spring-cloud-loadbalancer-->
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
<exclusions>
<exclusion>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-ribbon</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-loadbalancer</artifactId>
<version>3.0.2</version>
</dependency>

Nacos Config

引入 maven 依赖

electricity-common模块的 pom.xml 文件中引入Nacos Config Starter

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

配置 Nacos Config 元数据

在微服务模块中新建bootstrap.properties配置文件配置原数据,bootstrap.properties配置文件会优先于application.properties文件加载。

spring.application.name=electricity-coupon
spring.cloud.nacos.config.server-addr=127.0.0.1:8848

获取配置

完成上述两步后,应用会从 Nacos Config 中获取相应的配置,并添加在 Spring Environment 的 PropertySources 中。这里我们使用 @Value 注解来将对应的配置注入到 CouponController的 userName 和 age 字段,并添加@RefreshScope打开动态刷新功能。

@RefreshScope // 开启nacos配置动态刷新
@RestController
@RequestMapping("coupon/coupon")
public class CouponController {

// 获取配置信息
@Value("${coupon.user.name}")
private String name;
@Value("${coupon.user.age}")
private int age;
@RequestMapping("/test")
public R test() {
return R.ok().put("name", name).put("age", age);
}
}

启动应用

先启动 nacos server 程序,然后启动微服务项目,在浏览器输入项目地址获取信息。

localhost:7000/coupon/coupon/test

配置 Nacos DataID 数据

在 nacos 服务前端页面配置管理的配置列表中添加 DataID,DataID 为应用名.properties,选择配置格式,然后添加配置内容。

配置完成后,只需要修改这里的配置数据就可以自动获取新的数据,不需要再重新启动项目。

如果配置完成后,一切都正常,但是获取不到 nacos 配置的数据,应该是 springcloud 版本问题。

解决方案:在electricity-common模块添加依赖。

<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-bootstrap</artifactId>
<version>3.0.2</version>
</dependency>

命名空间和分组

nacos 中可以划分不同的命名空间和分组,默认的命名空间是 public,默认分组为 DEFAULT_GROUP。当配置文件较多时,我们可以配置不同的命名空间和分组对配置进行管理。

在 nacos 配置中心页面配置好命名空间和分组,然后在bootstrap.properties文件中添加配置。

# 命名空间ID
spring.cloud.nacos.config.namespace=dev
spring.cloud.nacos.config.group=coupon

加载多配置集

当配置信息比较多时,所有配置都放在一个文件里不好维护,我们可以把配置信息分离出来配置多个数据文件。

可以按照项目中配置的不同模块,将application.yml中的数据配置分离。例如按照数据源,mybatis,springcloud等划分成多个文件。然后按照之前的方式,新建配置文件,放在相应的命名空间和分组下。

bootstrap.properties文件中添加配置。

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

Gateway

新建模块

新建 springboot 模块,勾选 gateway 依赖。

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.5.1</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<groupId>com.laughing.electricity</groupId>
<artifactId>electricity-gateway</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>electricity-gateway</name>
<description>API网关</description>
<properties>
<java.version>1.8</java.version>
<spring-cloud.version>2020.0.3</spring-cloud.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-gateway</artifactId>
</dependency>

<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
<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>
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacos-config</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-bootstrap</artifactId>
<version>3.0.2</version>
</dependency>
<!--SpringCloud Feign在Hoxton.M2 RELEASED版本之后不再使用Ribbon而是使用spring-cloud-loadbalancer-->
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
<exclusions>
<exclusion>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-ribbon</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-loadbalancer</artifactId>
<version>3.0.2</version>
</dependency>
</dependencies>
</dependencyManagement>

<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>

</project>

配置 nacos

  • 在启动类上开启@EnableDiscoveryClient

  • application.properties 中配置 nacos 信息

spring.cloud.nacos.discovery.server-addr=127.0.0.1:8848
spring.application.name=electricity-gateway
server.port=8888
  • 新建 bootstrap.properites 配置文件
spring.application.name=electricity-gateway
spring.cloud.nacos.discovery.server-addr=127.0.0.1:8848
spring.cloud.nacos.config.namespace=dev
  • 新建 application.yml 配置文件
spring:
cloud:
gateway:
routes:
- id: zhibo8
uri: https://www.zhibo8.cc
predicates:
- Query=url,zhibo8
- id: bing
uri: https://bing.com
predicates:
- Query=url,bing

访问 localhost:8888/?bing可以直接跳转到 https://www.bing.com