我们在上面:
手把手教你Spring Cloud Alibaba教程:nacos安装
手把手教你Spring Cloud Alibaba教程:使用nacos实现服务注册与发现
了解了nacos和springCloudAlibaba的部署和使用,现在我们来了解下nacos作为配置中心应该如何使用。
Nacos除了实现了服务的注册发现之外,还将配置中心功能整合在了一起。通过Nacos的配置管理功能,我们可以将整个架构体系内的所有配置都集中在Nacos中存储。主要有以下几点:
- 分离的多环境配置,可以更灵活的管理权限,安全性更高
- 应用程序的打包更为纯粹,以实现一次打包,多处运行的特点
下面我们通过一个简单的例子来介绍如何在Nacos中创建配置内容以及如何在Spring Cloud应用中加载Nacos的配置信息。
nacos配置中心
创建配置
第一步:进入Nacos的控制页面,在配置列表功能页面中,点击右上角的“+”按钮,进入“新建配置”页面,如下图填写内容:
其中:
-
Data ID
:填入alibaba-nacos-config-client.properties
-
Group
:不修改,使用默认值DEFAULT_GROUP
-
配置格式
:选择Properties
-
配置内容
:应用要加载的配置内容,这里仅作为示例,做简单配置,比如:didispace.title=spring-cloud-alibaba-learning
创建应用
第一步:创建一个Spring Boot应用,可以命名为:alibaba-nacos-config-client
。
第二步:编辑pom.xml
,加入必要的依赖配置,比如:
<?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 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>org.example</groupId>
<artifactId>alibaba-nacos-config-client</artifactId>
<version>1.0</version>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.3.12.RELEASE</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
<java.version>1.8</java.version>
<spring-cloud.version>Hoxton.SR12</spring-cloud.version>
<spring-cloud-alibaba.version>2.2.9.RELEASE</spring-cloud-alibaba.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacos-config</artifactId>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.18.2</version>
<optional>true</optional>
</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-alibaba-dependencies</artifactId>
<version>${spring-cloud-alibaba.version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>
上述内容主要三部分:
-
parent
:定义spring boot的版本 -
dependencyManagement
:spring cloud的版本以及spring cloud alibaba的版本,由于spring cloud alibaba还未纳入spring cloud的主版本管理中,所以需要自己加入 -
dependencies
:当前应用要使用的依赖内容。这里主要新加入了Nacos的配置客户端模块:spring-cloud-starter-alibaba-nacos-config
。由于在dependencyManagement
中已经引入了版本,所以这里就不用指定具体版本了。
第三步:创建应用主类,并实现一个HTTP接口:
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.context.config.annotation.RefreshScope;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
/**
* @author za
* @create 2021/12/15 9:46
*/
@SpringBootApplication
public class ConfigClientApplication {
public static void main(String[] args) {
SpringApplication.run(ConfigClientApplication.class);
}
@Slf4j
@RestController
@RefreshScope
static class TestController {
@Value("${didispace.title:}")
private String title;
@GetMapping("/test")
public String hello() {
return title;
}
}
}
内容非常简单,@SpringBootApplication
定义是个Spring Boot应用;还定义了一个Controller,其中通过@Value
注解,注入了key为didispace.title
的配置(默认为空字符串),这个配置会通过/test
接口返回,后续我们会通过这个接口来验证Nacos中配置的加载。另外,这里还有一个比较重要的注解@RefreshScope
,主要用来让这个类下的配置内容支持动态刷新,也就是当我们的应用启动之后,修改了Nacos中的配置内容之后,这里也会马上生效。
第四步:创建配置文件bootstrap.properties
,并配置服务名称和Nacos地址
spring.application.name=alibaba-nacos-config-client
server.port=8002
spring.cloud.nacos.config.server-addr=nacos的ip地址:nacos端口
第五步:启动上面创建的应用。
2022-12-15 15:10:55.188 WARN 16116 --- [ main] c.a.c.n.c.NacosPropertySourceBuilder : Ignore the empty nacos configuration and get it based on dataId[alibaba-nacos-config-client] & group[DEFAULT_GROUP]
2022-12-15 15:10:55.206 INFO 16116 --- [ main] b.c.PropertySourceBootstrapConfiguration : Located property source: [BootstrapPropertySource {name='bootstrapProperties-alibaba-nacos-config-client.properties,DEFAULT_GROUP'}, BootstrapPropertySource {name='bootstrapProperties-alibaba-nacos-config-client,DEFAULT_GROUP'}]
在启动的时候,我们可以看到类似上面的日志信息,这里会输出应用程序要从Nacos中获取配置的dataId和group。如果在启动之后,发现配置信息没有获取到的时候,可以先从这里着手,看看配置加载的目标是否正确。
第六步:验证配置获取和验证动态刷新
用curl或者postman等工具,访问接口: localhost:8001/test
,一切正常的话,将返回Nacos中配置的spring-cloud-alibaba-learning
。然后,再通过Nacos页面,修改这个内容,点击发布之后,再访问接口,可以看到返回结果变了。
http://localhost:8002/test
同时,在应用的客户端,我们还能看到如下日志:
2022-12-15 15:11:58.906 INFO 16116 --- [ternal.notifier] o.s.c.e.event.RefreshEventListener : Refresh keys changed: [didispace.title]
在Nacos中修改了Key,在用到这个配置的应用中,也自动刷新了这个配置信息。
nacos配置规则详解
nacos配置规则我们拆解一下,主要有三个元素,它们与具体应用的配置内容对应关系如下:
- Data ID中的
alibaba-nacos-config-client
:对应客户端的配置spring.cloud.nacos.config.prefix
,默认值为${spring.application.name}
,即:服务名 - Data ID中的
properties
:对应客户端的配置spring.cloud.nacos.config.file-extension
,默认值为properties
- Group的值
DEFAULT_GROUP
:对应客户端的配置spring.cloud.nacos.config.group
,默认值为DEFAULT_GROUP
在采用默认值的应用要加载的配置规则就是:Data ID=${spring.application.name}.properties
,Group=DEFAULT_GROUP
。
下面,我们做一些假设例子,方便大家理解这些配置之间的关系:
例子一:如果我们不想通过服务名来加载,那么可以增加如下配置,就会加载到Data ID=example.properties
,Group=DEFAULT_GROUP
的配置内容了:
spring.cloud.nacos.config.prefix=example |
例子二:如果我们想要加载yaml格式的内容,而不是Properties格式的内容,那么可以通过如下配置,实现加载Data ID=example.yaml
,Group=DEFAULT_GROUP
的配置内容了:
spring.cloud.nacos.config.prefix=examplespring.cloud.nacos.config.file-extension=yaml |
例子三:如果我们对配置做了分组管理,那么可以通过如下配置,实现加载Data ID=example.yaml
,Group=DEV_GROUP
的配置内容了:
spring.cloud.nacos.config.prefix=examplespring.cloud.nacos.config.file-extension=yamlspring.cloud.nacos.config.group=DEV_GROUP |
nacos多环境管理
在Nacos中,本身有多个不同管理级别的概念,包括:Data ID
、Group
、Namespace
。只要利用好这些层级概念的关系,就可以根据自己的需要来实现多环境的管理。
下面,我就来介绍一下,可以使用的几种实现方式:
使用Data ID
与profiles
实现
Data ID
在Nacos中,我们可以理解为就是一个Spring Cloud应用的配置文件名。我们知道默认情况下Data ID
的名称格式是这样的:${spring.application.name}.properties
,即:以Spring Cloud应用命名的properties文件。
实际上,Data ID
的规则中,还包含了环境逻辑,这一点与Spring Cloud Config的设计类似。我们在应用启动时,可以通过spring.profiles.active
来指定具体的环境名称,此时客户端就会把要获取配置的Data ID
组织为:${spring.application.name}-${spring.profiles.active}.properties
。
第一步:先在Nacos中,根据这个规则,创建两个不同环境的配置内容。比如:
如上图,我们为alibaba-nacos-config-client
应用,定义了DEV和TEST的两个独立的环境配置。我们可以在里面定义不同的内容值(DEV是:didispace.title=spring-cloud-alibaba-DEV TEST是:didispace.title=spring-cloud-alibaba-TEST),以便后续验证是否真实加载到了正确的配置。
第二步:在alibaba-nacos-config-client
应用的配置文件中,增加环境配置:spring.profiles.active=DEV
第三步:启动应用,我们可以看到日志中打印了,加载的配置文件:
2021-12-15 15:37:05.978 WARN 14868 --- [ main] c.a.c.n.c.NacosPropertySourceBuilder : Ignore the empty nacos configuration and get it based on dataId[alibaba-nacos-config-client] & group[DEFAULT_GROUP]
2021-12-15 15:37:06.014 INFO 14868 --- [ main] b.c.PropertySourceBootstrapConfiguration : Located property source: [BootstrapPropertySource {name='bootstrapProperties-alibaba-nacos-config-client-DEV.properties,DEFAULT_GROUP'}, BootstrapPropertySource {name='bootstrapProperties-alibaba-nacos-config-client.properties,DEFAULT_GROUP'}, BootstrapPropertySource {name='bootstrapProperties-alibaba-nacos-config-client,DEFAULT_GROUP'}]
2021-12-15 15:37:06.018 INFO 14868 --- [ main] com.zhm.ConfigClientApplication : The following profiles are active: DEV
执行:
http://localhost:8002/test
这样就根据环境不同显示不同的内容了。
使用Group
实现
Group
在Nacos中是用来对Data ID
做集合管理的重要概念。所以,如果我们把一个环境的配置视为一个集合,那么也就可以实现不同环境的配置管理。对于Group
的用法并没有固定的规定,所以我们在实际使用的时候,需要根据我们的具体需求,可以是架构运维上对多环境的管理,也可以是业务上对不同模块的参数管理。为了避免冲突,我们需要在架构设计之初,做好一定的规划。这里,我们先来说说如何用Group
来实现多环境配置管理的具体实现方式。
动手试一试
第一步:先在Nacos中,通过区分Group
来创建两个不同环境的配置内容。比如:
如上图,我们为alibaba-nacos-config-client
应用,定义了DEV环境和TEST环境的两个独立的配置,这两个匹配与上一种方法不同,它们的Data ID
是完全相同的,只是GROUP
不同。
第二步:在alibaba-nacos-config-client
应用的配置文件中,增加Group
的指定配置:spring.cloud.nacos.config.group=DEV_GROUP
第三步:启动应用,我们可以看到日志中打印了,加载的配置文件:
2021-12-15 15:55:23.718 INFO 3216 --- [main] o.s.c.a.n.c.NacosPropertySourceBuilder : Loading nacos data, dataId: 'alibaba-nacos-config-client.properties', group: 'DEV_GROUP'
加载多个配置
通过之前的学习,我们已经知道Spring应用对Nacos中配置内容的对应关系是通过下面三个参数控制的:
- spring.cloud.nacos.config.prefix
- spring.cloud.nacos.config.file-extension
- spring.cloud.nacos.config.group
默认情况下,会加载Data ID=${spring.application.name}.properties
,Group=DEFAULT_GROUP
的配置。
假设现在有这样的一个需求:我们想要对所有应用的Actuator模块以及日志输出做统一的配置管理。所以,我们希望可以将Actuator模块的配置放在独立的配置文件actuator.properties
文件中,而对于日志输出的配置放在独立的配置文件log.properties
文件中。通过拆分这两类配置内容,希望可以做到配置的共享加载与统一管理。
这时候,我们只需要做以下两步,就可以实现这个需求:
第一步:在Nacos中创建Data ID=actuator.properties
,Group=DEFAULT_GROUP
和Data ID=log.properties
,Group=DEFAULT_GROUP
的配置内容
第二步:在Spring Cloud应用中通过使用spring.cloud.nacos.config.extension-configs
参数来配置要加载的这两个配置内容,比如:
spring.cloud.nacos.config.extension-configs[0].data-id=actuator.properties
spring.cloud.nacos.config.extension-configs[0].group=DEFAULT_GROUP
spring.cloud.nacos.config.extension-configs[0].refresh=true
spring.cloud.nacos.config.extension-configs[1].data-id=log.properties
spring.cloud.nacos.config.extension-configs[1].group=DEFAULT_GROUP
spring.cloud.nacos.config.extension-configs[1].refresh=true
可以看到,spring.cloud.nacos.config.ext-config
配置是一个数组List类型。每个配置中包含三个参数:data-id
、group
,refresh
;前两个不做赘述,与Nacos中创建的配置相互对应,refresh
参数控制这个配置文件中的内容时候支持自动刷新,默认情况下,只有默认加载的配置才会自动刷新,对于这些扩展的配置加载内容需要配置该设置时候才会实现自动刷新。
共享配置
通过上面加载多个配置的实现,实际上我们已经可以实现不同应用共享配置了。但是Nacos中还提供了另外一个便捷的配置方式,比如下面的设置与上面使用的配置内容是等价的:
spring.cloud.nacos.config.shared-configs[0].data-id=actuator.properties
spring.cloud.nacos.config.shared-configs[0].group=DEFAULT_GROUP
spring.cloud.nacos.config.shared-configs[0].refresh=true
spring.cloud.nacos.config.shared-configs[1].data-id=log.properties
spring.cloud.nacos.config.shared-configs[1].group=DEFAULT_GROUP
spring.cloud.nacos.config.shared-configs[1].refresh=true
###即将停用
spring.cloud.nacos.config.refreshable-dataids=actuator.properties,log.properties
-
spring.cloud.nacos.config.shared-configs
参数用来配置多个共享配置的Data Id,group,refresh
,多个的时候用用逗号分隔 -
spring.cloud.nacos.config.refreshable-dataids
参数用来定义哪些共享配置的Data Id
在配置变化时,应用中可以动态刷新,多个Data Id
之间用逗号隔开。如果没有明确配置,默认情况下所有共享配置都不支持动态刷新(后续即将停用)
配置加载的优先级
当我们加载多个配置的时候,如果存在相同的key时,我们需要深入了解配置加载的优先级关系。
在使用Nacos配置的时候,主要有以下三类配置:
- A: 通过
spring.cloud.nacos.config.shared-dataids
定义的共享配置 - B: 通过
spring.cloud.nacos.config.ext-config[n]
定义的加载配置 - C: 通过内部规则(
spring.cloud.nacos.config.prefix
、spring.cloud.nacos.config.file-extension
、spring.cloud.nacos.config.group
这几个参数)拼接出来的配置
要弄清楚这几个配置加载的顺序,我们从日志中也可以很清晰的看到,我们可以做一个简单的实验:
spring.cloud.nacos.config.extension-configs[0].data-id=actuator.properties
spring.cloud.nacos.config.extension-configs[0].group=DEFAULT_GROUP
spring.cloud.nacos.config.extension-configs[0].refresh=true
spring.cloud.nacos.config.shared-configs[0].data-id=log.properties
spring.cloud.nacos.config.shared-configs[0].group=DEFAULT_GROUP
spring.cloud.nacos.config.shared-configs[0].refresh=true
spring.cloud.nacos.config.refreshable-dataids=log.properties
后面加载的配置会覆盖之前加载的配置,所以优先级关系是:A < B < C