接上一篇文章: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。
按照上述规则依次匹配,优先匹配到谁就是谁。