5. 引入 Nacos Config 支持分布式配置

本节用于在本地环境引入 Nacos Config 的操作指引,不涉及对实验室环境的操作

Nacos Config 引入的方式有两种,即 Aliyun Java Initializr 引入和 Maven pom.xml 依赖。官方推荐使用 Aliyun Java Initializr 方式引入 Nacos Discovery,以便简化组件之间的依赖关系。

5.1 通过工程脚手架创建工程并引入 Nacos Config(推荐)

由于 Spring Cloud 组件的版本和依赖较为复杂,推荐读者使用工程脚手架构建应用工程。

上一步中,获取的代码事实上就是使用工程脚手架创建的。

读者选择偏好的 Web 浏览器访问工程脚手架,其资源网址为:https://start.aliyun.com/bootstrap.html
下文以 Google Chrome 浏览器为例,当网页加载后,首先,在 “项目基本信息” 部分输入 Group :“com.alibaba.cloud” 以及 Artifact:“nacos-config-sample”。然后,“组件依赖” 输入框搜索:“Nacos Config”,选择 “Nacos Configuration”,如下所示:
配置 - 图1
同上组件操作,增加 “Spring Web” 和 “Spring Boot Actuator” 组件: 配置 - 图2
组件选择后,点击 “生成” 高亮按钮。随后,平台将生成一个名为 “nacos-config-sample.zip” 的压缩文件,将其保存到本地目录,并解压该文件,工程目录将随之生成。打开目录下的 pom.xml 文件,不难发现 Nacos starter 声明其中(以下 XML 内容均来自于项目根路径中的 pom.xml 文件):

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


不过该 starter 并未指定版本,具体的版本声明在 com.alibaba.cloud:spring-cloud-alibaba-dependencies 部分:

  1. <dependencyManagement>
  2. <dependencies>
  3. <dependency>
  4. <groupId>com.alibaba.cloud</groupId>
  5. <artifactId>spring-cloud-alibaba-dependencies</artifactId>
  6. <version>${spring-cloud-alibaba.version}</version>
  7. <type>pom</type>
  8. <scope>import</scope>
  9. </dependency>
  10. <dependency>
  11. <groupId>org.springframework.boot</groupId>
  12. <artifactId>spring-boot-dependencies</artifactId>
  13. <version>${spring-boot.version}</version>
  14. <type>pom</type>
  15. <scope>import</scope>
  16. </dependency>
  17. </dependencies>
  18. </dependencyManagement>


其中,${spring-cloud-alibaba.version} 和 ${spring-boot.version} 分别为 Spring Cloud Alibaba 和 Spring Boot 组件依赖的版本,它们的版本定义在 <properties>元素中,即 2.2.1.RELEASE2.3.0.RELEASE

  1. <properties>
  2. <java.version>1.8</java.version>
  3. <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
  4. <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
  5. <spring-boot.version>2.3.0.RELEASE</spring-boot.version>
  6. <spring-cloud-alibaba.version>2.2.1.RELEASE</spring-cloud-alibaba.version>
  7. </properties>


如果读者非常熟悉 Maven 依赖管理的配置方式,可以考虑 Maven pom.xml 依赖 Nacos Config。

5.2 [高级] 通过 Maven pom.xml 依赖 Nacos Config

如果要在您的项目中使用 Nacos 来实现服务注册/发现,使用 group ID 为 com.alibaba.cloud和 artifact ID 为 spring-cloud-starter-alibaba-nacos-config的 starter。

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


该声明方式同样需要声明 com.alibaba.cloud:spring-cloud-alibaba-dependencies,内容与上小节相同,在此不再赘述。下一节将讨论如何使用 Nacos Config 支持分布式配置。

6. 使用 Nacos Config 实现分布式配置

本节,你将会修改工程,完成与 Nacos Config 的集成
使用 Nacos Config 实现分布式配置与 Spring Cloud Consul 和 Spring Cloud Zookeeper 的方式非常类似,仅需添加相关外部化配置即可工作。换言之,Nacos Config 同样不会侵入应用代码,方便应用整合和迁移,如果读者熟悉 Spring Cloud Consul 或 Spring Cloud Zookeeper 使用方式 的话,通常需要将 Consul 或 Zookeeper 服务进程预先部署,Nacos Config 也如此。

6.1 访问 Nacos 服务器

打开Nacos控制台(账号名/密码为 nacos/nacos),选择 “配置管理/配置列表”: 配置 - 图3
如果需要在本地运行,请参考 Nacos 官网
关于更多的 Nacos Server 版本,可以从 release 页面 下载最新的版本。

6.2 添加 Nacos 配置

点击“配置列表”页面右侧的 “+” 号(红色箭头所指): 配置 - 图4 浏览器跳转新页面,并填充内容如下: 配置 - 图5 其中,Data ID 由应用名(nacos-config-sample)+ 文件后缀名(.properties) 组成,点击“发布”按钮(红色箭头所指),配置内容为:

  1. user.name=nacos-config-sample
  2. user.age=90


发布成功后,控制台会出现提示弹出框。

6.3 修改应用配置

打开 bootstrap.properties
将注册中心地址改为刚才启动的 Nacos 服务端的地址(点我执行修改)
打开 application.properties
如果你在本地操作,可以参考如下的配置:
在 resources 目录下新建名为 “bootstrap.properties” 文件,并配置以下内容:

  1. spring.cloud.nacos.config.server-addr=127.0.0.1:8848
  2. spring.cloud.nacos.config.username=nacos
  3. spring.cloud.nacos.config.password=nacos


注意,Nacos Server 地址必须配置在 bootstrap.properties 文件。

注意: 1.当你使用域名的方式来访问 Nacos 时, spring.cloud.nacos.config.server-addr配置的方式为域名:port。 例如 Nacos 的域名为abc.com.nacos,监听的端口为 80,则 spring.cloud.nacos.config.server-addr=abc.com.nacos:80。 注意 80 端口不能省略。 2.当前环境的 nacos 服务端端口为65000;但是 nacos 的默认端口地址为8848;

6.4 添加读取 Nacos Config 实现

下面,我们为工程增加下面的代码,以实现在启动时读取和输出 nacos 中的配置项(点击右上角自动复制):

  1. package com.alibaba.cloud.nacosconfigsample;
  2. import javax.annotation.PostConstruct;
  3. import org.springframework.context.annotation.Configuration;
  4. import org.springframework.beans.factory.annotation.Value;
  5. @Configuration
  6. public class NacosConfigDemo {
  7. @Value("${user.name}")
  8. private String userName;
  9. @Value("${user.age}")
  10. private int userAge;
  11. @PostConstruct
  12. public void init() {
  13. System.out.printf("[init] user name : %s , age : %d%n", userName, userAge);
  14. }
  15. }

6.5 启动 Nacos Config 应用

首先,你需要编译你的工程

  1. cd /home/shell/nacos-config-sample && mvn clean package


首次编译可能需要花费 1~3 分钟;
待编译完成以后,启动程序

  1. java -jar /home/shell/nacos-config-sample/target/nacos-config-sample-0.0.1-SNAPSHOT.jar


启动完成后,你会看到下面的日志,代表启动过程中读取到了 nacos 服务端的配置数据:

[init] user name : nacos-config-sample , age : 90

如果在沙箱内启动应用,由于暂时还无法看到运行时的日志,可以通过WEB 控制器的方式查看参数,具体操作见下节。

7. 使用 Nacos Config 实现 Bean 动态刷新

7.1 使用 Nacos Config 实现 Bean @Value属性动态刷新

@RefreshScope
@Value(“${user.age}”)

7.2 使用 Nacos Config 实现 @ConfigurationPropertiesBean 属性动态刷新

标注 @RefreshScope@ConfigurationProperties

  1. package com.alibaba.cloud.nacosconfigsample;
  2. import org.springframework.boot.context.properties.ConfigurationProperties;
  3. import org.springframework.cloud.context.config.annotation.RefreshScope;
  4. @RefreshScope
  5. @ConfigurationProperties(prefix = "user")
  6. public class User {
  7. private String name;
  8. private int age;
  9. public String getName() {
  10. return name;
  11. }
  12. public void setName(String name) {
  13. this.name = name;
  14. }
  15. public int getAge() {
  16. return age;
  17. }
  18. public void setAge(int age) {
  19. this.age = age;
  20. }
  21. @Override
  22. public String toString() {
  23. return "User{" +
  24. "name='" + name + '\'' +
  25. ", age=" + age +
  26. '}';
  27. }
  28. }

7.3 使用 Nacos Config 监听实现 Bean 属性动态刷新

  • @Autowired依赖注入 NacosConfigManager
  • 新增 runner()方法,通过 NacosConfigManagerBean 获取 ConfigService,并增加了 AbstractListener( Listener抽象类)实现,监听 dataId = “nacos-config-sample.properties” 和 group = “DEFAULT_GROUP” 的配置内容 ```java import javax.annotation.PostConstruct; import javax.annotation.PreDestroy;

import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Value; import org.springframework.cloud.context.config.annotation.RefreshScope; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController;

import com.alibaba.cloud.nacos.NacosConfigManager; import com.alibaba.nacos.api.config.listener.AbstractListener;

@RestController @RefreshScope @EnableConfigurationProperties(User.class) public class NacosConfigDemo {

  1. @Value("${user.name}")
  2. private String userName;
  3. @Value("${user.age}")
  4. private int userAge;
  5. @Autowired
  6. private User user;
  7. @Autowired
  8. private NacosConfigManager nacosConfigManager;
  9. @Bean
  10. public ApplicationRunner runner() {
  11. return args -> {
  12. String dataId = "nacos-config-sample.properties";
  13. String group = "DEFAULT_GROUP";
  14. nacosConfigManager.getConfigService().addListener(dataId, group, new AbstractListener() {
  15. @Override
  16. public void receiveConfigInfo(String configInfo) {
  17. System.out.println("[Listener] " + configInfo);
  18. }
  19. });
  20. };
  21. }
  22. @PostConstruct
  23. public void init() {
  24. System.out.printf("[init] user name : %s , age : %d%n", userName, userAge);
  25. }
  26. @RequestMapping("/user")
  27. public String user() {
  28. return String.format("[HTTP] user name : %s , age : %d", userName, userAge);
  29. }
  30. @PreDestroy
  31. public void destroy() {
  32. System.out.printf("[destroy] user name : %s , age : %d%n", userName, userAge);
  33. }
  34. @RequestMapping("/user")
  35. public String user() {
  36. return "[HTTP] " + user;
  37. }

}

  1. <a name="fnpx1"></a>
  2. ## 8. Nacos Config 高级配置
  3. <a name="i9Ik9"></a>
  4. ### 8.1 支持自定义 namespace 的配置
  5. 首先看一下 Nacos 的 Namespace 的概念, [Nacos 概念](https://nacos.io/zh-cn/docs/concepts.html) 用于进行租户粒度的配置隔离。不同的命名空间下,可以存在相同的 Group 或 Data ID 的配置。Namespace 的常用场景之一是不同环境的配置的区分隔离,例如开发测试环境和生产环境的资源(如配置、服务)隔离等。 在没有明确指定 `${spring.cloud.nacos.config.namespace}`配置的情况下, 默认使用的是 Nacos 上 Public 这个namespae。如果需要使用自定义的命名空间,可以通过以下配置来实现:

spring.cloud.nacos.config.namespace=b3404bc0-d7dc-4855-b519-570ed34b62d7

  1. > 注:该配置必须放在 bootstrap.properties 文件中。此外 `spring.cloud.nacos.config.namespace`的值是 namespace 对应的 idid 值可以在 Nacos 的控制台获取。并且在添加配置时注意不要选择其他的 namespae,否则将会导致读取不到正确的配置
  2. <a name="viNoe"></a>
  3. ### 8.2 支持自定义 Group 的配置
  4. 在没有明确指定 `${spring.cloud.nacos.config.group}`配置的情况下, 默认使用的是 DEFAULT_GROUP 。如果需要自定义自己的 Group,可以通过以下配置来实现:

spring.cloud.nacos.config.group=DEVELOP_GROUP

  1. > 注:该配置必须放在 bootstrap.properties 文件中。并且在添加配置时 Group 的值一定要和 `spring.cloud.nacos.config.group`的配置值一致。
  2. <a name="VjmVP"></a>
  3. ### 8.3 支持自定义扩展的 Data Id 配置
  4. Spring Cloud Alibaba Nacos Config 0.2.1 版本后,可支持自定义 Data Id 的配置。关于这部分详细的设计可参考 [这里](https://github.com/spring-cloud-incubator/spring-cloud-alibaba/issues/141)。 一个完整的配置案例如下所示:

spring.application.name=opensource-service-provider spring.cloud.nacos.config.server-addr=127.0.0.1:8848

config external configuration

1、Data Id 在默认的组 DEFAULT_GROUP,不支持配置的动态刷新

spring.cloud.nacos.config.extension-configs[0].data-id=ext-config-common01.properties

2、Data Id 不在默认的组,不支持动态刷新

spring.cloud.nacos.config.extension-configs[1].data-id=ext-config-common02.properties spring.cloud.nacos.config.extension-configs[1].group=GLOBALE_GROUP

3、Data Id 既不在默认的组,也支持动态刷新

spring.cloud.nacos.config.extension-configs[2].data-id=ext-config-common03.properties spring.cloud.nacos.config.extension-configs[2].group=REFRESH_GROUP spring.cloud.nacos.config.extension-configs[2].refresh=true

  1. 可以看到:
  2. - 通过 `spring.cloud.nacos.config.extension-configs[n].data-id`的配置方式来支持多个 Data Id 的配置。
  3. - 通过 `spring.cloud.nacos.config.extension-configs[n].group`的配置方式自定义 Data Id 所在的组,不明确配置的话,默认是 DEFAULT_GROUP
  4. - 通过 `spring.cloud.nacos.config.extension-configs[n].refresh`的配置方式来控制该 Data Id 在配置变更时,是否支持应用中可动态刷新, 感知到最新的配置值。默认是不支持的。
  5. > 注:多个 Data Id 同时配置时,他的优先级关系是 `spring.cloud.nacos.config.extension-configs[n].data-id`其中 n 的值越大,优先级越高。 `spring.cloud.nacos.config.extension-configs[n].data-id`的值必须带文件扩展名,文件扩展名既可支持 properties,又可以支持 yaml/yml 此时 `spring.cloud.nacos.config.file-extension`的配置对自定义扩展配置的 Data Id 文件扩展名没有影响。
  6. 通过自定义扩展的 Data Id 配置,既可以解决多个应用间配置共享的问题,又可以支持一个应用有多个配置文件。 为了更加清晰的在多个应用间配置共享的 Data Id ,你可以通过以下的方式来配置:

配置支持共享的 Data Id

spring.cloud.nacos.config.shared-configs[0].data-id=common.yaml

配置 Data Id 所在分组,缺省默认 DEFAULT_GROUP

spring.cloud.nacos.config.shared-configs[0].group=GROUP_APP1

配置Data Id 在配置变更时,是否动态刷新,缺省默认 false

spring.cloud.nacos.config.shared-configs[0].refresh=true

  1. <br />可以看到:
  2. - 通过 `spring.cloud.nacos.config.shared-configs[n].data-id`来支持多个共享 Data Id 的配置。
  3. - 通过 `spring.cloud.nacos.config.shared-configs[n].group`来配置自定义 Data Id 所在的组,不明确配置的话,默认是 DEFAULT_GROUP
  4. - 通过 `spring.cloud.nacos.config.shared-configs[n].refresh`来控制该Data Id在配置变更时,是否支持应用中动态刷新,默认false
  5. <a name="UiyUl"></a>
  6. ### 8.4 配置的优先级
  7. Spring Cloud Alibaba Nacos Config 目前提供了三种配置能力从 Nacos 拉取相关的配置。
  8. - A: 通过 `spring.cloud.nacos.config.shared-configs[n].data-id`支持多个共享 Data Id 的配置
  9. - B: 通过 `spring.cloud.nacos.config.extension-configs[n].data-id`的方式支持多个扩展 Data Id 的配置
  10. - C: 通过内部相关规则(应用名、应用名+ Profile )自动生成相关的 Data Id 配置
  11. 当三种方式共同使用时,他们的一个优先级关系是:A < B < C
  12. <a name="dMZDa"></a>
  13. ### 8.5 完全关闭配置
  14. 通过设置 spring.cloud.nacos.config.enabled = false 来完全关闭 Spring Cloud Nacos Config
  15. <a name="W4feL"></a>
  16. ### 8.6 更多高级配置
  17. 更多关于 Nacos Config Starter 的配置项如下所示:
  18. | 配置项 | Key | 默认值 | 说明 |
  19. | --- | --- | --- | --- |
  20. | 服务端地址 | `spring.cloud.nacos.config.server-addr` | | Nacos Server 启动监听的ip地址和端口 |
  21. | 配置对应的 DataId | `spring.cloud.nacos.config.name` | | 先取 prefix,再取 name,最后取 spring.application.name |
  22. | 配置对应的 DataId | `spring.cloud.nacos.config.prefix` | | 先取 prefix,再取 name,最后取 spring.application.name |
  23. | 配置内容编码 | `spring.cloud.nacos.config.encode` | | 读取的配置内容对应的编码 |
  24. | GROUP | `spring.cloud.nacos.config.group` | `DEFAULT_GROUP` | 配置对应的组 |
  25. | 文件扩展名 | `spring.cloud.nacos.config.fileExtension` | `properties` | 配置项对应的文件扩展名,目前支持 properties yaml(yml) |
  26. | 获取配置超时时间 | `spring.cloud.nacos.config.timeout` | `3000` | 客户端获取配置的超时时间(毫秒) |
  27. | 接入点 | `spring.cloud.nacos.config.endpoint` | | 地域的某个服务的入口域名,通过此域名可以动态地拿到服务端地址 |
  28. | 命名空间 | `spring.cloud.nacos.config.namespace` | | 常用场景之一是不同环境的配置的区分隔离,例如开发测试环境和生产环境的资源(如配置、服务)隔离等 |
  29. | AccessKey | `spring.cloud.nacos.config.accessKey` | | 当要上阿里云时,阿里云上面的一个云账号名 |
  30. | SecretKey | `spring.cloud.nacos.config.secretKey` | | 当要上阿里云时,阿里云上面的一个云账号密码 |
  31. | Nacos Server 对应的 context path | `spring.cloud.nacos.config.contextPath` | | Nacos Server 对外暴露的 context path |
  32. | 集群 | `spring.cloud.nacos.config.clusterName` | | 配置成Nacos集群名称 |
  33. | 共享配置 | `spring.cloud.nacos.config.sharedDataids` | | 共享配置的 DataId, "," 分割 |
  34. | 共享配置动态刷新 | `spring.cloud.nacos.config.refreshableDataids` | | 共享配置中需要动态刷新的 DataId, "," 分割 |
  35. | 自定义 Data Id 配置 | `spring.cloud.nacos.config.extConfig` | | |
  36. <a name="8U7MU"></a>
  37. ## 9. Nacos Config Actuator Endpoint
  38. Nacos Config 内部提供了一个 Endpoint, 对应的 Endpoint ID `nacos-config`,其 Actuator Web Endpoint URI `/actuator/nacos-config`
  39. > 注:使用 Nacos Config Spring Cloud 1.x 版本的话,其 URI 地址则为 `/nacos-config`
  40. 其中,Endpoint 暴露的 json 中包含了三种属性:
  41. - NacosConfigProperties: 当前应用 Nacos 的基础配置信息
  42. - RefreshHistory: 配置刷新的历史记录
  43. - Sources: 当前应用配置的数据信息
  44. 由于 Aliyun Java Initializr 所生成的应用工程默认激活 Spring Boot Actuator EndpointsJMX Web),具体配置存放在 `application.properties`文件中,同时,Actuator Web 端口设置为 8081,内容如下:

management.endpoints.jmx.exposure.include= management.endpoints.web.exposure.include= management.endpoint.health.show-details=always

Actuator Web 访问端口

management.server.port=8081

  1. <br />因此,应用 nacos-config-sample 无需调整,直接访问:[http://127.0.0.1:8081/actuator/nacos-config](http://127.0.0.1:8081/actuator/nacos-config?spm=5176.12026607.tutorial.9.9c7732e2z771Hm),服务响应的内容如下:

{ “NacosConfigProperties”: { “serverAddr”: “127.0.0.1:8848”, “username”: “”, “password”: “”, “encode”: null, “group”: “DEFAULT_GROUP”, “prefix”: null, “fileExtension”: “properties”, “timeout”: 3000, “maxRetry”: null, “configLongPollTimeout”: null, “configRetryTime”: null, “enableRemoteSyncConfig”: false, “endpoint”: null, “namespace”: null, “accessKey”: null, “secretKey”: null, “contextPath”: null, “clusterName”: null, “name”: null, “sharedConfigs”: null, “extensionConfigs”: null, “refreshEnabled”: true, “sharedDataids”: null, “refreshableDataids”: null, “extConfig”: null, “configServiceProperties”: { “secretKey”: “”, “namespace”: “”, “username”: “”, “enableRemoteSyncConfig”: “false”, “configLongPollTimeout”: “”, “configRetryTime”: “”, “encode”: “”, “serverAddr”: “127.0.0.1:8848”, “maxRetry”: “”, “clusterName”: “”, “password”: “”, “accessKey”: “”, “endpoint”: “” } }, “RefreshHistory”: [ ], “Sources”: [ { “lastSynced”: “2020-09-14 11:11:37”, “dataId”: “nacos-config-sample.properties” }, { “lastSynced”: “2020-09-14 11:11:37”, “dataId”: “nacos-config-sample” } ] } ```