Spring Cloud Alibaba Nacos

时间:2023-12-15 18:18:38

1. Spring Cloud Alibaba 介绍

Spring Cloud Alibaba 为分布式应用程序开发提供了一站式解决方案。它包含了开发分布式应用程序所需的所有组件,使得你可以轻松地使用Spring Cloud开发应用程序。

使用Spring Cloud Alibaba,只需要添加一些注释和少量配置即可将Spring Cloud应用程序连接到Alibaba的分布式解决方案,并使用Alibaba中间件构建分布式应用程序系统。

特性:

  • 流量控制和服务降级:Sentinel进行流量控制,断路和系统自适应保护。
  • 服务注册和发现:实例可以在Nachos中注册,并且客户端可以使用Spring管理的Bean发现实例。支持Ribbon。
  • 分布式配置:使用Nacos作为数据存储。
  • 事件驱动:建立与Spring Cloud Stream RocketMQ Binder连接的高度可扩展的事件驱动型微服务。
  • 消息总线:利用Spring Cloud Bus RocketMQ链接分布式系统的节点。
  • 分布式事务:支持高性能、易于使用的分布式事务。
  • Dubbo RPC :通过Dubbo RPC扩展Spring Cloud服务之间调用的通信协议。
  • 阿里云对象存储:阿里云对象存储服务(OSS)是一种加密、安全、经济高效且易于使用的对象存储服务,可让您在云中存储,备份和存档大量数据。

依赖管理:

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

2. Spring Cloud Alibaba Nacos Discovery

Nacos是一个易于使用的动态服务发现、配置和服务管理平台。

服务注册与发现:服务发现是微服务体系架构中的关键组件之一。在这样的体系结构中,为每个客户端手动配置服务列表可能是不太现实的,并且使动态扩展极为困难。Nacos Discovery帮助您自动将服务注册到Nacos Server,并且Nacos Server会跟踪服务并动态刷新服务列表。

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

Nacos Discovery集成了Netflix Ribbon 、RestTemplate或OpenFeign,可用于服务之间的调用

2.1. Start a Provider Application

首先,创建一个提供者服务

 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 <modelVersion>4.0.0</modelVersion>
5 <parent>
6 <groupId>org.springframework.boot</groupId>
7 <artifactId>spring-boot-starter-parent</artifactId>
8 <version>2.1.11.RELEASE</version>
9 <relativePath/> <!-- lookup parent from repository -->
10 </parent>
11 <groupId>com.cjs.example</groupId>
12 <artifactId>nacos-discovery-provider-example</artifactId>
13 <version>0.0.1-SNAPSHOT</version>
14 <name>nacos-discovery-provider-example</name>
15
16 <properties>
17 <java.version>1.8</java.version>
18 <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
19 <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
20 </properties>
21
22 <dependencyManagement>
23 <dependencies>
24 <dependency>
25 <groupId>org.springframework.cloud</groupId>
26 <artifactId>spring-cloud-dependencies</artifactId>
27 <version>Greenwich.SR4</version>
28 <type>pom</type>
29 <scope>import</scope>
30 </dependency>
31 <dependency>
32 <groupId>com.alibaba.cloud</groupId>
33 <artifactId>spring-cloud-alibaba-dependencies</artifactId>
34 <version>2.1.0.RELEASE</version>
35 <type>pom</type>
36 <scope>import</scope>
37 </dependency>
38 </dependencies>
39 </dependencyManagement>
40
41 <dependencies>
42 <dependency>
43 <groupId>org.springframework.boot</groupId>
44 <artifactId>spring-boot-starter-actuator</artifactId>
45 </dependency>
46 <dependency>
47 <groupId>org.springframework.boot</groupId>
48 <artifactId>spring-boot-starter-web</artifactId>
49 </dependency>
50 <dependency>
51 <groupId>com.alibaba.cloud</groupId>
52 <artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
53 </dependency>
54 </dependencies>
55
56 <build>
57 <plugins>
58 <plugin>
59 <groupId>org.springframework.boot</groupId>
60 <artifactId>spring-boot-maven-plugin</artifactId>
61 </plugin>
62 </plugins>
63 </build>
64
65 </project>

application.properties

 server.port=
spring.application.name=nacos-provider
spring.cloud.nacos.discovery.server-addr=127.0.0.1:8848
management.endpoints.web.exposure.include=*

如果您不想使用Nacos进行服务注册和发现,可以设置spring.cloud.nacos.discovery为false

 1 package com.cjs.example.nacos;
2
3 import org.springframework.boot.SpringApplication;
4 import org.springframework.boot.autoconfigure.SpringBootApplication;
5 import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
6 import org.springframework.web.bind.annotation.GetMapping;
7 import org.springframework.web.bind.annotation.PathVariable;
8 import org.springframework.web.bind.annotation.RestController;
9
10 @SpringBootApplication
11 @EnableDiscoveryClient
12 public class NacosDiscoveryProviderExampleApplication {
13
14 public static void main(String[] args) {
15 SpringApplication.run(NacosDiscoveryProviderExampleApplication.class, args);
16 }
17
18 @RestController
19 public class EchoController {
20 @GetMapping(value = "/echo/{string}")
21 public String echo(@PathVariable String string) {
22 return "Hello Nacos Discovery " + string;
23 }
24 }
25
26 } 

注意,务必先启动Nacos

wget https://github.com/alibaba/nacos/releases/download/1.1.4/nacos-server-1.1.4.tar.gz
tar -zxf nacos-server-1.1.4.tar.gz
cd nacos/bin
sh startup.sh -m standalone
sh shutdown.sh

2.2. Start a Consumer Application

创建一个消费者服务

 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 <modelVersion>4.0.0</modelVersion>
5 <parent>
6 <groupId>org.springframework.boot</groupId>
7 <artifactId>spring-boot-starter-parent</artifactId>
8 <version>2.1.11.RELEASE</version>
9 <relativePath/> <!-- lookup parent from repository -->
10 </parent>
11 <groupId>com.cjs.example</groupId>
12 <artifactId>nacos-discovery-consumer-example</artifactId>
13 <version>0.0.1-SNAPSHOT</version>
14 <name>nacos-discovery-consumer-example</name>
15
16 <properties>
17 <java.version>1.8</java.version>
18 <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
19 <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
20 </properties>
21
22 <dependencyManagement>
23 <dependencies>
24 <dependency>
25 <groupId>org.springframework.cloud</groupId>
26 <artifactId>spring-cloud-dependencies</artifactId>
27 <version>Greenwich.SR4</version>
28 <type>pom</type>
29 <scope>import</scope>
30 </dependency>
31 <dependency>
32 <groupId>com.alibaba.cloud</groupId>
33 <artifactId>spring-cloud-alibaba-dependencies</artifactId>
34 <version>2.1.0.RELEASE</version>
35 <type>pom</type>
36 <scope>import</scope>
37 </dependency>
38 </dependencies>
39 </dependencyManagement>
40
41 <dependencies>
42 <dependency>
43 <groupId>org.springframework.boot</groupId>
44 <artifactId>spring-boot-starter-actuator</artifactId>
45 </dependency>
46 <dependency>
47 <groupId>org.springframework.boot</groupId>
48 <artifactId>spring-boot-starter-web</artifactId>
49 </dependency>
50 <dependency>
51 <groupId>com.alibaba.cloud</groupId>
52 <artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
53 </dependency>
54 <dependency>
55 <groupId>org.springframework.cloud</groupId>
56 <artifactId>spring-cloud-starter-netflix-ribbon</artifactId>
57 </dependency>
58 <dependency>
59 <groupId>org.springframework.cloud</groupId>
60 <artifactId>spring-cloud-starter-openfeign</artifactId>
61 </dependency>
62 </dependencies>
63
64 <build>
65 <plugins>
66 <plugin>
67 <groupId>org.springframework.boot</groupId>
68 <artifactId>spring-boot-maven-plugin</artifactId>
69 </plugin>
70 </plugins>
71 </build>
72
73 </project> 

application.properties

 server.port=
spring.application.name=nacos-consumer
spring.cloud.nacos.discovery.server-addr=127.0.0.1:8848
management.endpoints.web.exposure.include=* 

使用RestTemplate或者FeignClient调用远程服务

 1 package com.cjs.example.nacos;
2
3 import org.springframework.beans.factory.annotation.Autowired;
4 import org.springframework.beans.factory.annotation.Value;
5 import org.springframework.boot.SpringApplication;
6 import org.springframework.boot.autoconfigure.SpringBootApplication;
7 import org.springframework.cloud.client.ServiceInstance;
8 import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
9 import org.springframework.cloud.client.loadbalancer.LoadBalancerClient;
10 import org.springframework.cloud.openfeign.EnableFeignClients;
11 import org.springframework.cloud.openfeign.FeignClient;
12 import org.springframework.context.annotation.Bean;
13 import org.springframework.web.bind.annotation.GetMapping;
14 import org.springframework.web.bind.annotation.PathVariable;
15 import org.springframework.web.bind.annotation.RestController;
16 import org.springframework.web.client.RestTemplate;
17
18 @SpringBootApplication
19 @EnableDiscoveryClient
20 @EnableFeignClients
21 public class NacosDiscoveryConsumerExampleApplication {
22
23 public static void main(String[] args) {
24 SpringApplication.run(NacosDiscoveryConsumerExampleApplication.class, args);
25 }
26
27
28 @RestController
29 public class NacosController{
30
31 @Autowired
32 private LoadBalancerClient loadBalancerClient;
33 @Autowired
34 private RestTemplate restTemplate;
35
36 @Value("${spring.application.name}")
37 private String appName;
38
39 /**
40 * 使用RestTemplate调用远程服务
41 */
42 @GetMapping("/echo/app-name")
43 public String echoAppName(){
44 // Access through the combination of LoadBalanceClient and RestTemplate
45 ServiceInstance serviceInstance = loadBalancerClient.choose("nacos-provider");
46 String path = String.format("http://%s:%s/echo/%s",serviceInstance.getHost(),serviceInstance.getPort(),appName);
47 System.out.println("request path:" +path);
48 return restTemplate.getForObject(path,String.class);
49 }
50
51 // Instantiate RestTemplate Instance
52 @Bean
53 public RestTemplate restTemplate(){
54 return new RestTemplate();
55 }
56
57
58 // ----------------------------------------
59
60 @Autowired
61 private EchoService echoService;
62 /**
63 * 使用FeignClient调用远程服务
64 */
65 @GetMapping("/sayHello")
66 public String sayHello() {
67 return echoService.echo("hello");
68 }
69 }
70
71 /**
72 * 使用FeignClient进行远程调用
73 */
74 @FeignClient(name = "nacos-provider")
75 public interface EchoService {
76 @GetMapping("/echo/{str}")
77 String echo(@PathVariable("str") String str);
78 }
79 }

访问地址:

http://127.0.0.1:8082/echo/app-name

http://127.0.0.1:8082/sayHello

Spring Cloud Alibaba Nacos

看一下Nacos控制台,默认用户名密码是nacos/nacos

http://127.0.0.1:8848/nacos/index.html

Spring Cloud Alibaba Nacos

更多Nacos Discovery配置,请参见 com.alibaba.cloud.nacos.NacosDiscoveryProperties

Spring Cloud Alibaba Nacos

3. Spring Cloud Alibaba Nacos Config

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

Nacos Config使用DataIdGROUP来确定配置。

首先,在控制台创建好配置项

Spring Cloud Alibaba Nacos

Spring Cloud Alibaba Nacos

然后,新建一个bootstrap.properties文件

bootstrap.properties

1 spring.application.name=nacos-config-example
2 spring.cloud.nacos.config.server-addr=127.0.0.1:8848
3
4 #spring.cloud.nacos.config.shared-dataids=nacos-config-dev.properties
5 #spring.cloud.nacos.config.file-extension=properties
6 #spring.cloud.nacos.config.group=DEFAULT_GROUP
7
8 spring.cloud.nacos.config.ext-config[0].data-id=nacos-config-dev.properties
9 spring.cloud.nacos.config.ext-config[0].refresh=true

更多配置项,参见 com.alibaba.cloud.nacos.NacosConfigProperties

application.properties

1 server.port=
2 management.endpoints.web.exposure.include=*

NacosConfigExampleApplication.java

 1 package com.cjs.example.nacos;
2
3 import org.springframework.boot.SpringApplication;
4 import org.springframework.boot.autoconfigure.SpringBootApplication;
5 import org.springframework.context.ConfigurableApplicationContext;
6
7 import java.util.concurrent.TimeUnit;
8
9 @SpringBootApplication
10 public class NacosConfigExampleApplication {
11
12 public static void main(String[] args) throws InterruptedException {
13 ConfigurableApplicationContext applicationContext = SpringApplication.run(NacosConfigExampleApplication.class, args);
14
15 while (true) {
16 String userName = applicationContext.getEnvironment().getProperty("user.name");
17 String userAge = applicationContext.getEnvironment().getProperty("user.age");
18 System.err.println("user name:" + userName + "; age: " + userAge);
19 TimeUnit.SECONDS.sleep();
20 }
21 }
22
23 } 

读取配置还可以使用@Value注解,例如:

 1 package com.cjs.example.nacos;
2
3 import org.springframework.beans.factory.annotation.Value;
4 import org.springframework.cloud.context.config.annotation.RefreshScope;
5 import org.springframework.web.bind.annotation.GetMapping;
6 import org.springframework.web.bind.annotation.RestController;
7
8 @RefreshScope
9 @RestController
10 public class TestController {
11
12 @Value("${user.name}")
13 private String username;
14
15 @Value("${user.age}")
16 private Integer userAge;
17
18 @GetMapping("/hi")
19 public String hi() {
20 System.out.println(username);
21 System.out.println(userAge);
22 return "ok";
23 }
24
25 } 

修改配置后,立即生效

关于配置项,可以看代码

Spring Cloud Alibaba Nacos

Spring Cloud Alibaba Nacos

3.1. Nacos Config 支持 profile level

Nacos Config 加载配置时,会加载两种格式的配置文件:

${spring.application.name}.${file-extension:properties}

${spring.application.name}-${profile}.${file-extension:properties}

如果你需要用不同的配置来区分不同的环境,你可以使用${spring.profiles.active}来指定

什么意思呢?举个例子:

这跟Spring Boot里面的application-dev.properties、application-test.properties类似,

只不过用Nacos Config的话,我们就不需要application-${profile}.properties这样的配置文件了

假设你的应用名称是hello,那么无论是hello.properties,还是hello-dev.properties,Nacos Config都认识,都会加重它们

Spring Cloud Alibaba Nacos

约定优于配置

约定优于配置

约定优于配置

如果按照上面的配置,那么在bootstrap.properties中根本需要指定data-id,只需指定spring.profiles.active

 spring.application.name=nacos-config-example
spring.cloud.nacos.config.server-addr=127.0.0.1:8848
spring.profiles.active=prod 

当然啦,在真实环境中,肯定是通过-Dspring.profiles.active=<profile>参数来指定的

3.2. Nacos Config 数据结构

在Nacos Config中,是通过DataId和Group来确定一个配置的

DataID的格式是这样的:

 ${prefix} - ${spring.profiles.active} . ${file-extension}
  • prefix :默认值是spring.application.name的值,也可以通过spring.cloud.nacos.config.prefix来指定
  • spring.profiles.active :是与当前环境一致的profile
  • file-extension :所配置的内容的数据格式,默认是properties

group的默认值是DEFAULT_GROUP,可以通过spring.cloud.nacos.config.group指定

自动注入

Nacos Config Starter实现org.springframework.cloud.bootstrap.config.PropertySourceLocator接口,并将顺序设置为0。

在Spring Cloud应用程序的启动阶段,从Nacos Server端获取相应的数据,并将获取的数据转换为PropertySource并注入到Spring Environment的PropertySources属性中。 因此@Value注解也可以直接获取Nacos Server端的配置。

动态刷新

默认情况下,Nacos Config Starter为成功获取到的所有Nacos配置项添加监听功能。 当它检测到服务器配置中的更改时,它将实时触发org.springframework.cloud.context.refresh.ContextRefresher的刷新方法。

通过spring.cloud.nacos.config.enabled=false可以禁用自动刷新

强烈推荐,在class上添加 @RefreshScope 或者 @ConfigurationProperties

自定义namespace

命名空间用于隔离不同租户的配置。在不同的命名空间中,Group和Data ID可以相同。命名空间的典型场景是隔离不同环境的配置,例如,开发/测试环境与生产环境(配置和服务等)之间的隔离。

默认的命名空间是Public,也就是说不指定命名空间就是Public

可以通过spring.cloud.nacos.config.namespace来手动指定

自定义Groups

通过spring.cloud.nacos.config.group指定

自定义Data Id

例如:

 spring.application.name=opensource-service-provider
spring.cloud.nacos.config.server-addr=127.0.0.1:8848 # config external configuration
# 1. Data Id is in the default group of DEFAULT_GROUP, and dynamic refresh of configurations is not supported.
spring.cloud.nacos.config.ext-config[0].data-id=ext-config-common01.properties # 2. Data Id is not in the default group, and dynamic refresh of configurations is not supported.
spring.cloud.nacos.config.ext-config[1].data-id=ext-config-common02.properties
spring.cloud.nacos.config.ext-config[1].group=GLOBALE_GROUP # 3. Data Id is not in the default group and dynamic referesh of configurations is supported.
spring.cloud.nacos.config.ext-config[2].data-id=ext-config-common03.properties
spring.cloud.nacos.config.ext-config[2].group=REFRESH_GROUP
spring.cloud.nacos.config.ext-config[2].refresh=true 

可以看到这里配置了3个Data Id

当配置多个Data Id时,优先级由spring.cloud.nacos.config.ext-config[n].data-id中的n决定。数值越大,优先级越高。

spring.cloud.nacos.config.ext-config[n].data-id必须有文件扩展,也就是说要有后缀。可以是properties,或者 yaml/yml。

设置spring.cloud.nacos.config.file-extension对自定义Data Id的文件扩展没有任何影响,也就是说此配置项对自定义data id不生效。

自定义Data ID的配置允许在多个应用程序之间共享配置,还可以为一个应用程序支持多种配置。例如:

 spring.cloud.nacos.config.shared-dataids=bootstrap-common.properties,all-common.properties
spring.cloud.nacos.config.refreshable-dataids=bootstrap-common.properties

spring.cloud.nacos.config.shared-dataids 指定了哪些Data Id是共享的(公共的),用逗号分隔

spring.cloud.nacos.config.refreshable-dataids 用于控制哪些Data Id可以动态刷新,如果不配置,则所有的共享数据都不会动态刷新

注意:

  • 如果用spring.cloud.nacos.config.shared-dataids配置了多个共享data id,那么它们之间的优先级取决于它们再配置文件中出现的顺序,也就是说后面的优先级高于前面的。
  • 当使用spring.cloud.nacos.config.shared-dataids时,后面必须带文件扩展名。可以是 properties 或者 yaml/yml。spring.cloud.nacos.config.file-extension对自定义的data id文件扩展名不起作用。
  • 当使用spring.cloud.nacos.config.refreshable-dataids指定哪些data id支持动态刷新时,被指定的这些data id要带上文件扩展名,换言之,要和之前指定的data-id的一样

4. 文档

Spring Cloud Alibaba 特性:

  • 流量控制和服务降级:支持WebServlet 、WebFlux 、OpenFeign 、RestTemplate 、Dubbo访问限制和服务降级功能。 它可以在运行时通过控制台实时修改限流和降级规则,并且还支持限流和降级的监控指标。
  • 服务注册和发现:可以注册服务,并且客户端可以使用Spring托管的bean发现实例,自动集成Ribbon。
  • 分布式配置:支持分布式系统中的外部配置,配置更改后实时自动刷新。
  • RPC服务:扩展Spring Cloud客户端RestTemplate和OpenFeign以支持调用Dubbo RPC服务。
  • 事件驱动:支持构建与共享消息传递系统连接的高度可扩展的事件驱动型微服务。
  • 分布式事务:支持具有高性能和易用性的分布式事务解决方案。
  • 阿里云对象存储:大规模,安全,低成本和高度可靠的云存储服务。支持随时随地在任何应用程序中存储和访问任何类型的数据。

https://spring.io/projects/spring-cloud

https://spring.io/projects/spring-cloud-alibaba

https://github.com/alibaba/spring-cloud-alibaba

https://spring-cloud-alibaba-group.github.io/github-pages/greenwich/spring-cloud-alibaba.html

https://github.com/alibaba