1. 简介
Nacos 提供用于存储配置和其他元数据的 key/value 存储,为分布式系统中的外部化配置提供服务器端和客户端支持。使用 Spring Cloud Alibaba Nacos Config,您可以在 Nacos Server 集中管理你 Spring Cloud 应用的外部属性配置。
Spring Cloud Alibaba Nacos Config 是 Config Server 和 Client 的替代方案,客户端和服务器上的概念与 Spring Environment 和 PropertySource 有着一致的抽象,在特殊的 bootstrap 阶段,配置被加载到 Spring 环境中。当应用程序通过部署管道从开发到测试再到生产时,您可以管理这些环境之间的配置,并确保应用程序具有迁移时需要运行的所有内容。Nacos 的获取和启动方式可以参考 Nacos 官网。
注:如果读者是阿里云商业化组件 ANS 或 ACM 用户,请使用 Nacos Config 代替对应的组件。
2. 学习目标
- 使用 Nacos Config 作为 Spring Cloud 分布式配置
- 使用 Nacos Config 实现 Bean 动态刷新
- 了解 Nacos Config 高级配置
3. 详细内容
- 快速上手:使用 Nacos Config 作为外部化配置源
- 多文件扩展名支持:以 YAML 文件扩展名为例,讨论 Nacos Config 多文件扩展名支持
- 动态配置更新:演示 @RefreshScope 特性,实现 Bean 动态刷新
- 自定义扩展:自定义 namespace、Group 以及 Data Id 的配置扩展
- 运维特性:演示 Nacos Config 高级外部化配置以及 Endpoint 内部细节
4. 快速上手
4.1 如何引入 Nacos Config 支持分布式配置
Nacos Config 引入的方式同样也有两种,即 Aliyun Java Initializr 引入和 Maven pom.xml 依赖。官方推荐使用 Aliyun Java Initializr 方式引入 Nacos Discovery,以便简化组件之间的依赖关系。
4.1.1 [偷懒] 直接在沙箱里查看应用代码
点击 链接,直接访问沙箱环境,这里会有为你准备好的案例代码^_^。
4.1.2 [简单] 通过 Aliyun Java Initializr 创建工程并引入 Nacos Config(推荐)
由于 Spring Cloud 组件的版本和依赖较为复杂,推荐读者使用 Aliyun Java Initializr 构建应用工程。
读者选择偏好的 Web 浏览器访问 Aliyun Java Initializr,其资源网址为:https://start.aliyun.com/bootstrap.html
下文以 Google Chrome 浏览器为例,当网页加载后,首先,在 “项目基本信息” 部分输入 Group :“com.alibaba.cloud” 以及 Artifact:“nacos-config-sample”。然后,“组件依赖” 输入框搜索:“Nacos Config”,选择 “Nacos Configuration”,如下所示:
同上组件操作,增加 “Spring Web” 和 “Spring Boot Actuator” 组件:
组件选择后,点击 “生成” 高亮按钮。随后,平台将生成一个名为 “nacos-config-sample.zip” 的压缩文件,将其保存到本地目录,并解压该文件,工程目录将随之生成。打开目录下的 pom.xml 文件,不难发现 Nacos starter 声明其中(以下 XML 内容均来自于项目根路径中的 pom.xml 文件):
<dependency> <groupId>com.alibaba.cloud</groupId> <artifactId>spring-cloud-starter-alibaba-nacos-config</artifactId> </dependency>
不过该 starter 并未指定版本,具体的版本声明在 com.alibaba.cloud:spring-cloud-alibaba-dependencies 部分:
<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> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-dependencies</artifactId> <version>${spring-boot.version}</version> <type>pom</type> <scope>import</scope> </dependency> </dependencies> </dependencyManagement>
其中,${spring-cloud-alibaba.version} 和 ${spring-boot.version} 分别为 Spring Cloud Alibaba 和 Spring Boot 组件依赖的版本,它们的版本定义在 <properties>
元素中,即 2.2.1.RELEASE 和 2.3.0.RELEASE:
<properties> <java.version>1.8</java.version> <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding> <spring-boot.version>2.3.0.RELEASE</spring-boot.version> <spring-cloud-alibaba.version>2.2.1.RELEASE</spring-cloud-alibaba.version> </properties>
如果读者非常熟悉 Maven 依赖管理的配置方式,可以考虑 Maven pom.xml 依赖 Nacos Config。
4.1.3 [高级] 通过 Maven pom.xml 依赖 Nacos Config
如果要在您的项目中使用 Nacos 来实现服务注册/发现,使用 group ID 为 com.alibaba.cloud
和 artifact ID 为 spring-cloud-starter-alibaba-nacos-config
的 starter。
<dependency> <groupId>com.alibaba.cloud</groupId> <artifactId>spring-cloud-starter-alibaba-nacos-config</artifactId> </dependency>
该声明方式同样需要声明 com.alibaba.cloud:spring-cloud-alibaba-dependencies,内容与上小节相同,在此不再赘述。下一节将讨论如何使用 Nacos Config 支持分布式配置。
4.2 使用 Nacos Config 实现分布式配置
使用 Nacos Config 实现分布式配置与 Spring Cloud Consul 和 Spring Cloud Zookeeper 的方式非常类似,仅需添加相关外部化配置即可工作。换言之,Nacos Config 同样不会侵入应用代码,方便应用整合和迁移,如果读者熟悉 Spring Cloud Consul 或 Spring Cloud Zookeeper 使用方式 的话,通常需要将 Consul 或 Zookeeper 服务进程预先部署,Nacos Config 也如此。
4.2.1 启动 Nacos 服务器
我们为开发者提供了一套免费的 Nacos Server :进入 http://139.196.203.133:8848/nacos/ 查看控制台(账号名/密码为 nacos-configuration/nacos-configuration),选择 “配置管理/配置列表”:
由于服务是公共免费的,为了做好隔离,所以分布式配置的功能,请选择在 sandbox-configuration 的命名空间下操作。
具体启动方式参考 Nacos 官网。
关于更多的 Nacos Server 版本,可以从 release 页面 下载最新的版本。
4.2.2 添加 Nacos 配置
点击“配置列表”页面右侧的 “+” 号(红色箭头所指):
浏览器跳转新页面,并填充内容如下:
其中,Data ID 由应用名(nacos-config-sample)+ 文件后缀名(.properties) 组成,点击“发布”按钮(红色箭头所指),配置内容为:
user.name=nacos-config-sample user.age=90
发布成功后,控制台会出现提示弹出框。
特别提醒
图片中的 Data ID 中的应用名,使用的是 nacos-config-sample 。如果使用我们提供的 Nacos Server ,由于多个用户同时使用,可能存在应用名冲突的问题。建议修改为跟别人都不重复的应用名:
spring.application.name=xxxxxx
替换上面的xxxxx部分
4.2.3 配置应用 Nacos Config Server 地址
回到应用 nacos-config-sample 工程,在 resources 目录下新建名为 “bootstrap.properties" 文件,并配置以下内容:
spring.cloud.nacos.config.server-addr=139.196.203.133:8848 spring.cloud.nacos.config.username=nacos-configuration spring.cloud.nacos.config.password=nacos-configuration spring.cloud.nacos.config.namespace=sandbox-configuration
注意,Nacos Server 地址必须配置在 bootstrap.properties 文件。
注意当你使用域名的方式来访问 Nacos 时,
spring.cloud.nacos.config.server-addr
配置的方式为域名:port。例如 Nacos 的域名为abc.com.nacos,监听的端口为 80,则spring.cloud.nacos.config.server-addr=abc.com.nacos:80
。注意 80 端口不能省略。
4.2.4 添加读取 Nacos Config 实现
修改 nacos-config-sample 引导类,如下所示:
@SpringBootApplication public class NacosConfigSampleApplication { @Value("${user.name}") private String userName; @Value("${user.age}") private int userAge; @PostConstruct public void init() { System.out.printf("[init] user name : %s , age : %d%n", userName, userAge); } public static void main(String[] args) { SpringApplication.run(NacosConfigSampleApplication.class, args); } }
4.2.5 启动 Nacos Config 应用
运行 nacos-config-sample 引导类 NacosConfigSampleApplication
,观察控制台结果(截取关键日志信息):
[init] user name : nacos-config-sample , age : 90
如果在沙箱内启动应用,由于暂时还无法看到运行时的日志,可以通过WEB 控制器的方式查看参数,具体操作见 5.1 节。
5. 使用 Nacos Config 实现 Bean 动态刷新
Nacos Confg 支持标准 Spring Cloud @RefreshScope
特性,即应用订阅某个 Nacos 配置后,当配置内容变化时,Refresh Scope Beans 中的绑定配置的属性将有条件的更新。所谓的条件是指 Bean 必须:
- 必须条件:Bean 的声明类必须标注
@RefreshScope
- 二选一条件:
- 属性(非 static 字段)标注
@Value
@ConfigurationProperties
Bean
除此之外,Nacos Confg 也引入了 Nacos Client 底层数据变化监听接口,即 com.alibaba.nacos.api.config.listener.Listener
。下面的内容将分别讨论这三种不同的使用场景。
Nacos Client:Nacos 客户端 API,也是 Nacos Config 底层依赖
5.1 使用 Nacos Config 实现 Bean @Value
属性动态刷新
基于应用 nacos-config-sample 修改,将引导类 NacosConfigSampleApplication
标注@RefreshScope
和 @RestController
,使得该类变为 Spring MVC REST 控制器,同时具备动态刷新能力,具体代码如下:
@SpringBootApplication @RestController @RefreshScope public class NacosConfigSampleApplication { @Value("${user.name}") private String userName; @Value("${user.age}") private int userAge; @PostConstruct public void init() { System.out.printf("[init] user name : %s , age : %d%n", userName, userAge); } @RequestMapping("/user") public String user() { return String.format("[HTTP] user name : %s , age : %d", userName, userAge); } public static void main(String[] args) { SpringApplication.run(NacosConfigSampleApplication.class, args); } }