图源:
Nacos 不仅可以作为服务的注册中心,还可以作为配置管理服务。
基础
在 Nacos 中添加配置文件
首先,要在 Nacos 管理面板中为服务添加配置文件。
在 配置管理->配置列表 页面点击 +
以添加新的配置文件:
这里的 Data ID 是有格式要求的,一般是 服务名-profile.后缀名
的格式,这里的 profile 指的是 Spring 中的 profiles.active
配置项的值,也就是用于区分不同开发环境的标识,比如 dev、test、prd 等。
后缀名没有严格要求,对于
yaml
文件,后缀名可以是yml
或yaml
。
依赖
子模块中要使用 Nacos 的配置管理功能,需要添加依赖:
<!--nacos配置管理依赖-->
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacos-config</artifactId>
</dependency>
bootstrap
还需要配置一些必要信息(如服务名、profile、Nacos 配置后缀名等)以便能够正确匹配到 Nacos 中设置的配置文件。
但需要注意的是,这些配置信息不能在application.yml
中填写,因为 SpringBoot 启动后会先从 Nacos 中拉取配置文件,再读取本地配置文件applicaton.yml
,将两者合并作为最终的配置信息。
所以 Nacos 配置管理所需的配置信息要填写到bootstrap.yaml
中,这个文件在application.yml
之前被读取。
spring
application
name shopping-user # 服务名称
profiles
active dev #开发环境,这里是dev
cloud
nacos
server-addr localhost 8848 # Nacos地址
config
file-extension yaml # 文件后缀名
application.yaml
中的重复配置信息可以被删除。
测试
为了验证可以正确从 Nacos 读取配置信息,可以添加一个接口:
public class UserController {
"${pattern.dateformat}")
( private String dateformat;
// ...
"/now")
( public Result<String> getNowTime(){
String time = LocalDateTime.now().format(DateTimeFormatter.ofPattern(dateformat));
return Result.success(time);
}
}
启动子模块 shopping-user 的实例,请求 http://localhost:8081/user/now 接口,就能看到如下输出:
{
"data": "2023-07-17 20:12:51",
"errorMsg": "",
"errorCode": "",
"success": true
}
热更新
使用 Nacos 统一管理配置文件的好处是可以进行配置的“热更新”,即在服务实例没有重启的情况下更新配置信息。
默认情况下通过@Value
读取到的配置内容是不会热更新的,比如我们将 Nacos 中的配置信息修改为:
pattern
dateformat yyyy/MM/dd HH mm ss
再次访问接口不会看到时间格式改变。
@Value
如果使用@Value
注解读取配置信息,要使用 Nacos 热更新配置信息,就要给所属类添加@RefreshScope
注解:
public class UserController {
"${pattern.dateformat}")
( private String dateformat;
// ...
}
现在重启子模块 shopping-user,访问接口,之后再修改 Nacos 配置内容为:
pattern
dateformat yyyy年MM月dd日 HH mm ss
再次访问接口,可以看到接口返回内容变为:
{
"data": "2023年07月17日 20:19:50",
"errorMsg": "",
"errorCode": "",
"success": true
}
这说明热更新已经生效。
一旦 Nacos 的配置信息发生变化,它就会通知相关的实例,相关的实例就会重新从 Nacos 读取配置信息。
@ConfigurationProperties
除了使用@Value
读取配置信息,还可以使用@ConfigurationProperties
注解的类来读取配置信息,此时不需要做任何改变就可以从 Nacos 热更新配置信息。
这里改用@ConfigurationProperties
标记的类读取配置信息:
@Component
@ConfigurationProperties(prefix = "pattern")
@Getter
@Setter
public class PatternProperties {
private String dateformat;
}
测试接口修改为:
@RestController
@RequestMapping("/user")
@Validated
public class UserController {
@Autowired
private PatternProperties patternProperties;
// ...
@GetMapping("/now")
public Result<String> getNowTime(){
String dateformat = patternProperties.getDateformat();
String time = LocalDateTime.now().format(DateTimeFormatter.ofPattern(dateformat));
return Result.success(time);
}
}
注意,这里并没有使用
@RefreshScope
注解。
进行类似之前的测试,可以观察到热更新已经生效。从这个角度讲,使用@ConfigurationProperties
读取配置是优于@Value
的。
共享配置
实际上子模块 shopping-user 启动时可以观察到从多个 Nacos 配置读取信息的记录:
[add-listener] ok, tenant=, dataId=shopping-user, group=DEFAULT_GROUP, cnt=1 [add-listener] ok, tenant=, dataId=shopping-user.yaml, group=DEFAULT_GROUP, cnt=1 [add-listener] ok, tenant=, dataId=shopping-user-dev.yaml, group=DEFAULT_GROUP, cnt=1
这说明如果我们配置不带 profile 的配置文件 shopping-user.yaml,同样会被子模块 shopping-user 读取。
这里 shopping-user.yaml 和 shopping-user-dev.yaml 的关系类似于 application.yml 和 application-dev.yml 的关系。也就是说,对于多环境下共享且需要配置到 Nacos 的配置信息,我们可以保存到 [服务名].[后缀名] 这样的 Nacos 配置文件中。
验证
下面我们来验证一下。
修改 8082 端口对应实例的配置,将 Active profiles 修改为test
:
这是一个快捷设置,也可以在启动参数中添加
-Dprofiles.active=test
。
启动实例,现在我们有两个 shopping-user 实例,一个是 dev 环境,一个是 test 环境。
在 Nacos 上添加配置文件:
shopping-user.yaml
pattern:
common: common propertie value
shopping-user-test.yaml
pattern:
dateformat: yyyy年MM月dd日 HH:mm:ss
PatternProperties 类添加一个属性:
public class PatternProperties {
private String dateformat;
private String common;
}
增加一个接口:
public class UserController {
@GetMapping("/properties")
public Result<PatternProperties> properties() {
return Result.success(patternProperties);
}
}
请求 http://localhost:8081/user/properties
{
"data": {
"dateformat": "yyyy/MM/dd/ HH:mm:ss",
"common": "common propertie value"
},
"errorMsg": "",
"errorCode": "",
"success": true
}
请求 http://localhost:8082/user/properties
{
"data": {
"dateformat": "yyyy年MM月dd日 HH:mm:ss",
"common": "common propertie value"
},
"errorMsg": "",
"errorCode": "",
"success": true
}
这说明 dev 环境的实例会读取 Nacos 上的 [服务名]-dev.[后缀名] 的配置文件,test 环境的实例会读取 [服务名]-test.[后缀名] 的配置文件。但他们都会读取 [服务名].[后缀名] 这个配置文件。
优先级
如果 shopping.yaml、shopping-dev.yaml、本地的 application.yml 都配置了同一个配置项,那么优先级顺序是怎样的?
可以用以下的方式进行验证。
修改 shopping-user.yaml
pattern:
common: common propertie value
common-and-dev: in common file
common-and-local: in common file
修改 shopping-user-dev.yaml
pattern:
dateformat: yyyy/MM/dd/ HH:mm:ss
common-and-dev: in dev file
修改 shopping-user 的本地配置文件 application.yml:
pattern:
common-and-local: in local file
修改 PatternProperties.java
public class PatternProperties {
private String dateformat;
private String common;
private String commonAndDev;
private String commonAndLocal;
}
重新运行 shopping-user 实例并访问接口 http://localhost:8081/user/properties
{
"data": {
"dateformat": "yyyy/MM/dd/ HH:mm:ss",
"common": "common propertie value",
"commonAndDev": "in dev file",
"commonAndLocal": "in common file"
},
"errorMsg": "",
"errorCode": "",
"success": true
}
这说明具体环境的 Nacos 配置文件(这里是 shopping-dev.yaml)优先于通用 Nacos 配置文件(这里是 shopping.yaml),通用 Nacos 配置文件优先于本地配置文件(这里是 application.yml)。
换言之,远程配置文件(Nacos 上的配置文件)优先于本地配置,而具体环境的远程配置文件要优先于通用的远程配置文件。
The End,谢谢阅读。
本文的完整示例代码可以从获取。
文章评论