nacos中配了一个数字,springboot取回来怎么变了

背景

对于java开发人员来说,nacos想必不陌生了,我们这边是拿来做配置中心为主。我这边的习惯用法是,在bootstrap.yml中配置nacos相关的配置、profile:

image-20250719110643445

然后呢,可以看到,nacos是支持启用或者不启用的,如果为true,就会使用nacos上的配置;我本地开发的时候,随时会把配置改来改去,我一般设置为false,不启用,此时就会使用本地的application-dev.yml中的配置。

开发得差不多了,再切换成使用nacos中配置,测一下就差不多了。

{
  "name": "spring.cloud.nacos.config.enabled",
  "type": "java.lang.Boolean",
  "description": "enable nacos config or not.",
  "defaultValue": true
},

结果呢,最近遇到个小问题。如下所示,有个appCode,这个配置项,是一个应用的唯一编码,开发环境配置如下,不论使用启用nacos,这块在程序中获取的配置都是正确的。

image-20250719111648452

对应的spring中接收配置的代码如下:

image-20250719112336234

然后,转到测试环境后,换成了如下配置,也就是code变了,结果程序中取出来,就成了:

image-20250719111338376

image-20250719112232276

appCode怎么是266啥的,我当时和测试同事仔细检查了下,确认没配置错误。

那,这是咋回事呢

定位过程

排除nacos问题

由于是测试环境,网络都是通的,我直接在本地ide连测试环境,复现了下问题,抓了个本地和nacos之间的包:

image-20250719112701214

看了下一点问题没有。接下来就是看代码怎么处理的了。

propertysouece

先弄个field断点,看看写入时候的栈。其实如果对nacos熟悉的话,也可以正向排查,从nacos获取到配置后的处理过程开始看,我这里就先按照反向流程来。

image-20250719112819387

然后就看到断点停住了,进来的值确实不对:

image-20250719113333307

把栈往上翻了翻,发现是在创建bean的过程中调用这块方法的。我们知道,一个bean的创建,一般会有:调用构造函数--》注入field的值(比如那些设置了@autowired的field、或者是我这这种注解了@ConfigurationProperties(prefix = "app")的,等等)--》调用init方法或afterpropertiesSet方法等。

此时,我的栈就处于第二步,此时bean已经通过构造函数弄出来了,正在注入ConfigurationProperties相关属性的值。

翻到上面的caller栈,发现下面这个地方,获取到的bound字段的值已经是2开头,是错的了,那看来就是这个地方,取到了错误的值,那就这里打个断点再来。

image-20250719113912260

这次从上面断点进来后,发现进入了一个findProperty的方法,如下,主要就是根据app.app-list-need-query-todo-num[0].app-code这么个属性,要获取到对应的value,这也正常,要先获取到值,才能设置到bena里。

image-20250719114458850

可以看到,获取property主要是从propertySource中获取。这个property是啥类型呢,

org.springframework.boot.context.properties.source.SpringIterableConfigurationPropertySource,里面有另一个propertySource字段,这个字段的类型是:org.springframework.cloud.bootstrap.config.BootstrapPropertySource,而下图可看到,BootstrapPropertySource中的delegate字段,才指向真正的propertySource,即NacosPropertySource

image-20250719114811789

这里我们跟进去后,发现,property的格式不太一致,nacos中的存储都是驼峰格式,而这里获取配置的property是中划线格式,所以这次是获取不到的。

image-20250719115151449

不过,spring做了兼容,会对property进行转换,变成驼峰格式再来找一次:

image-20250719115405870

这次能找到了,但找到的是错误的,所以,我们还得看看nacosPropertySource中的值,为啥是错的。

nacosPropertySource中的值,存放在source这个字段中,类型是LinkedHashMap,我们就看看这个map是什么时候赋值的。

image-20250719115517861

我们发现,这个source应该是构造函数时候,设置进来的,如下:

image-20250719115659644

找了下调用这个构造函数的地方,如下,这里就会去先获取nacos中的配置,然后调用构造函数,我们看了下,发现下面红框的propertySource中已经是错误的了,得再打个断点跟进去

image-20250719121013642

loadNacosData

下面这个方法中,先就是去nacos服务端获取到配置,然后再进行解析,可以看到,从服务端取到的是对的,那就是解析的问题,继续跟进去:

image-20250719121522023

由于nacos中配置支持多种格式,如下图所示,有多种解析器,我们这边是yaml,类型是:org.springframework.boot.env.YamlPropertySourceLoader,这个loader是spring-boot自带的:

image-20250719121752844

image-20250719122227249

这个org.springframework.boot.env.YamlPropertySourceLoader实际自己并不能独立完成yaml格式文件的解析,而是依赖另一个jar包:

    <dependency>
      <groupId>org.yaml</groupId>
      <artifactId>snakeyaml</artifactId>
      <version>1.30</version>
      <scope>compile</scope>
    </dependency>

image-20250719122512634

image-20250719122425049

yaml

yaml这个具体的解析逻辑就比较复杂了,可以使用条件断点,不然很难debug。

image-20250719122816898

下面可以看到,如果这个字符串,是0开头,就认为是8进制了,且会去掉开头的0,如:01011003,由于首位为0,认为是8进制,然后去掉符号位,值为:1011003

image-20250719123002108

然后把1011003转成8进制数字,变成了266755

image-20250719123144064

image-20250719123221903

image-20250719125612535

为啥开发环境时的010190那个code没转成8进制了,可能是转换失败了(但我发现改成010190后,没走上面那段逻辑,里面yaml解析挺复杂,就没继续跟了)。

解决方式

由于是进制转换的问题,我这里的解决方式是,直接在nacos用字符串来配置,避免这些数字转换问题。

image-20250719125905497

posted @ 2025-07-19 13:07  三国梦回  阅读(402)  评论(5)    收藏  举报