接上一篇文章:nacos 获取配置提示config data not exist

上一篇文章表示nacos本身没有问题了,这篇文章主要介绍spring boot读取nacos时遇到的一些坑。

1.加载配置遇到问题

我们首先创建两个配置

spring boot项目中bootstrap.yml的配置信息如下:

spring:
  application:
    name: producer-service-dev # 服务名称
  profiles:
    active: dev #开发环境,这里是dev
  cloud:
    nacos:
      config:
        server-addr: localhost:8848 # Nacos作为配置中心地址
        file-extension: yml # 文件后缀名
        group: DEFAULT_GROUP
        prefix: test-dev

nacos的配置信息如下:

启动spring boot时,看到控制台有加载

Located property source: [BootstrapPropertySource {name='bootstrapProperties-test-dev-dev.yml,DEFAULT_GROUP'}, BootstrapPropertySource {name='bootstrapProperties-test-dev.yml,DEFAULT_GROUP'}, BootstrapPropertySource {name='bootstrapProperties-test-dev,DEFAULT_GROUP'}]

但是启动失败,控制台报错:

org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'userController': Injection of autowired dependencies failed; nested exception is java.lang.IllegalArgumentException: Could not resolve placeholder 'student.name' in value "${student.name}"

这个报错表示使用@Value注解无法读取nacos中的配置。

按照上一篇文章的方法,在控制台访问了这个配置项,发现正常返回数据。

按照这个思路来说,cmd方式下能获取到,那么一定是spring boot配置的问题,于是在网上找了很多文章看,但是最终还是没有解决。

开始想debug,查看一下到底有没有正常获取到。找到nacos的jar包,在client下有一个NacosPropertySourceBuilder类,里面有个loadNacosData方法,我们在开头和结尾打上断点,然后启动spring boot来观察一下。

第一次进入,放行到下图位置,可以看到,dataId为test-dev,能读取到数据data,里面有我们配置的信息。

第二次进入断点时,dataId变成了test-dev.yml了。这个dataId在nacos的配置中没有,所以自然也获取不到。

第三次进入时,dataId变成了test-dev-dev.yml,因为nacos中根本没有这个名字,所以返回的data为空。

但是再继续放行的情况下就会报错:

org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'userController': Injection of autowired dependencies failed; nested exception is java.lang.IllegalArgumentException: Could not resolve placeholder 'student.name' in value "${student.name}"

一开始我坚信是我spring boot的配置项写的对,查了一天的资料改来改去就是报错,结果第二天,随手创建了一个新的配置文件,然后启动后突然发现好了。

于是赶紧打开nacos的历史版本功能,开始对比两个配置文件。最终发现了问题

原来字段名和数据之间要加空格,可能是一开始写的时候没注意忘了加了。

修改后,正常启动spring boot,也可以正常访问。

2.加载顺序的疑问

在上面的问题中发现了spring boot会自动加载三个配置文件,分布是test-dev、test-dev.yml、test-dev-dev.yml。

有几个问题。

(1)spring boot是如何决定和拼凑出这三个配置文件的dataId的?

(2)如果nacos中同时存在这三个配置文件,那么最终读取的内容是什么?

对于上述问题(2),我们可以简单验证一下,我们创建三个配置文件,分别命名为上述名字

三个配置文件的内容分别如下:

student:
    name: test-dev
student:
    name: test-dev.yml
student:
    name: test-dev-dev.yml

然后启动spring boot,查看接口返回的数据

结合前面查询的资料,破案了。

3.简单总结

网络上可以查询到nacos服务和配置之间有一套匹配规则:

${preifx}-${spring.profile.active}.${file-extenion}
prefix 默认为 spring.application.name的值也就是服务名称,也可以通过spring.cloud.nacos.config.prefix来指定
spring.profile.active为当前环境对应的profile
file-extenion 为配置文件的格式,服务中可以通过spring.cloud.nacos.config.file-extension来配置,目前只支持properties和ymal类型

按照我们开头的bootstrap.yml配置文件

spring:
  application:
    name: producer-service-dev # 服务名称
  profiles:
    active: dev #开发环境,这里是dev
  cloud:
    nacos:
      config:
        server-addr: localhost:8848 # Nacos作为配置中心地址
        file-extension: yml # 文件后缀名
        group: DEFAULT_GROUP
        prefix: test-dev

如果完全匹配规则,那么dataId就是 test-dev-dev.yml (但是debug时顺序是相反的,难道是栈,先进后出?)。然后把spring.profile.active这个属性去掉,变成test-dev.yml,最后再把file-extenion后缀去掉,变成test-dev。

按照上述规则依次匹配,优先匹配到谁就是谁。