nacos-group / nacos-spring-project

Nacos ECO Project for Spring Framework
https://nacos.io/
Apache License 2.0
754 stars 309 forks source link

通过@NacosValue autoRefreshed监听配置条目如果value包含"$"可能会导致autoRefreshed功能失效 #335

Open zhoujinsy opened 8 months ago

zhoujinsy commented 8 months ago

Issue Description

问题版本:问题发现版本nacos-spring-context-1.1.1.jar, 目前最新的release版本为nacos-spring-context-1.1.2.jar问题仍存在 问题表现: 系统启动后, 配置了@NacosValue autoRefresh的nacos 配置条目有固定次数配置变更无法autoRefresh

Describe what happened (or what feature you want)

   1 问题原因  
         1.1 在spring容器启动时, 会生成针对nacos配置刷新的监听器bean,  在nacos配置发生变更时, 监听器会遍历所有使用@NacosValue autorefresh的bean列表, 通过属性或者方法设置对应key的新value
         1.2 如果存在nacos配置条目的value包含$,并且配置了@NacosValue autoRefresh监听, 在进行占位符替换时, 会校验$后面必需是"{"或者数字"1~9" ,否则会抛出异常, 导致设置配置新值的循环中断, 排在该配置条目后面的配置无法刷新  
         1.3 由于每次占位符替换前会设置新的md5值到对应监听key上, 比对是基于key新旧值的md5值做的比对,故只会在第一次监听刷新时产生异常中断, 后续其他key的value刷新, 会认为value值包含$的key已刷新成功, 直接跳过, 故后续其他配置条目更改时刷新不会受到影响
  2 问题影响   
         2.1 配置条目的value包含$并且$后续字符不是{或者数字1~9 的配置项无法自动刷新   
         2.2 不定数量的其他配置了autoRefresh的配置条目, 在启动后,前几次变更配置无法自动刷新, 无法自动刷新的次数同应用中监听的value包含$并且$后续字符不是{或者数字1~9 的配置条目数一致.   
         2.3 如果同时变更value包含$并且$后续字符不是{或者数字1~9 的配置条目和其他条目, 则均无法刷新成功
         2.4 异常堆栈   

image 3 复现方法 3.1 nacos中新建application.properties文件, 录入如下配置 demoConfigItem0=qtest0 demoConfigItem1={"password":"(.password):|=(?!ENC[(][a-zA-Z0-9]+[)])(?![$][{].+[}])(.+)"} demoConfigItem2=dtest2 demoConfigItem3=atest3 demoConfigItem4=pre,prod,green 3.2 在bean中监听所有的配置条目, 启动服务 image 3.3 将上述配置改为 demoConfigItem0=qtest+c0 demoConfigItem1={"password":"(.password):|=(?!ENC[(][a-zA-Z0-9]+[)])(?![$][{].+[}])(.+)"} demoConfigItem2=dtest2+c2 demoConfigItem3=atest3+c3 demoConfigItem4=pre,prod,green+c4 可以看到, 只有部分key能刷新成功 3.4 再次将上述配置改为 demoConfigItem0=qtest+c0+c01 demoConfigItem1={"password":"(.password):|=(?!ENC[(][a-zA-Z0-9]+[)])(?![$][{].+[}])(.+)"} demoConfigItem2=dtest2+c2+c21 demoConfigItem3=atest3+c3+c31 demoConfigItem4=pre,prod,green+c4+c41 可以看到,所有key都能能刷新成功 3.5 再次将上述配置改为 demoConfigItem0=qtest+c0+c01+c02 demoConfigItem1={"password":"(.password):|=(?!ENC[(][a-zA-Z0-9]+[)])(?![$][{].+[}])(.+)"}+c12 demoConfigItem2=dtest2+c2+c21+c22 demoConfigItem3=atest3+c3+c31+c32 demoConfigItem4=pre,prod,green+c4+c41+c42 可以看到,所有key均刷新不成功

Describe what you expected to happen

        问题主要原因是配置包含$的value值时, 在进行占位符替换时, 有异常抛出导致刷新配置的循环中断, 并且异常被当作ignore异常被吞掉
        希望做如下改进:
               改进方案1
                     1、配置包含$的value值时, 在进行占位符替换时, 有异常抛出, 将异常信息以error日志的输出出来, 便于问题排查
                     2、异常的try catch放到每一个配置条目value值刷新的内部, 避免某一个刷新异常影响其他配置条目的刷新
               改进方案2
                     1、 不使用jdk原生的replaceAll方法进行占位符替换, 自定义占位符替换方法, 能够兼容$后续字符不是{或者数字1~9的情况

How to reproduce it (as minimally and precisely as possible)

在NacosValueAnnotationBeanPostProcessor类的下图位置进行try catch, 输出error日志 image