nacos无法动态刷新配置前言 本篇文章主要描述在网上没有找到答案时,对框架不熟悉的情况,如何通过debug源码,去解决
前言
本篇文章主要描述在网上没有找到答案时,对框架不熟悉的情况,如何通过debug源码,去解决问题。所以这篇文章记录了自己解决问题的思路、以及debug
流程。
问题描述
按照网上的配置都改好了,也去官网找了资料,还是没法动态刷新。只有重启的时候会重新拉取配置。
-
环境: springboot2.4.5、 nacos服务器版本2.4.1、nacos 客户端依赖0.2.11
-
配置:
nacos.config.server-addr=http://xxxx.xx.xx:8848 nacos.config.namespace=bec4dc34-7d71-4c6b-a24d-4ac2e429b7be nacos.config.username=nacos nacos.config.password=nacos # 开启自动刷新 nacos.config.auto-refresh=true nacos.config.enable-remote-sync-config=true nacos.config.config-long-poll-timeout=46000
-
代码:
@RestController @RequestMapping("properties") public class ReadNacosProperties { @NacosValue(value = "${me.user:test}", autoRefreshed = true) private String meUser; @GetMapping("/q") public Object test(){ return meUser; } }
@SpringBootApplication(exclude = DataSourceAutoConfiguration.class) @NacosPropertySource(dataId = "jeecgBoot") public class NacosApplication { public static void main(String[] args) { SpringApplication.run(NacosApplication.class, args); } }
我这代码和配置没啥问题吧,能正常拉取配置,就是改了远程配置,访问接口还是拿到的是历史配置。
解决方案
先把我的解决方案说了吧,解决思路下面再慢慢分析。 配置文件增加以下两个配置:
nacos.config.data-id=jeecgBoot
nacos.config.bootstrap.log-enable=true
当然还有其他的配置方式,下面的debug
流程主要就是解释为什么要配置这两个属性
排查思路
先去官网和百度看看了,都没有解决我的问题,只有自己跟一下源码了。 下面看看官网的使用教程,以及官方博客给出的一些解决思路,最后就是看我如何通过debug
源码解决无法动态刷新的问题的。
官网步骤:
实际按照官网这种写法是没有问题的,能自动刷新。我当时启动类上面只配置了
dataId
,autoRefreshed
我是配置在配置文件,如果我当时注意到了就会不会有这篇文章了。(ps:想知道为什么就往下面看吧)
官网博客:
debug源码解决问题
debug
思路主要是从@NacosValue
注解入手,毕竟这个注解上面配置autoRefreshed
。
确定@NacosValue
处理逻辑
关键类NacosValueAnnotationBeanPostProcessor.class
、和方法doWithAnnotation
下面方法逻辑就是对
@NacosValue
注解相关信息的封装然后放到Map
里面。这个地方实际是没有去set值或者更新值得,只是在获取@NacosValue
注解相关信息,然后封装到一个Map
对象(placeholderNacosValueTargetMap
)。
通过打断点看堆栈信息、或者查看方法的引用我们可以发现都是在
postProcessBeforeInitialization
方法中去调用的,这就是和spring
bean
的初始化流程接轨了,还记得这个接口吗?
确定placeholderNacosValueTargetMap
的使用逻辑
查看map
的调用方法NacosValueAnnotationBeanPostProcessor.onApplicationEvent
可以看到属性的刷新也是通过
spring
的事件发布机制来处理的,接下来就简单了,我们就确认什么时候发布的NacosConfigReceivedEvent
确认事件发布逻辑
通过debug
发现没有调用事件发布的方法,这是我们就一层一层往上debug
,直到进入下面的方法ClientWorker.executeConfigListen()
因为
CachData
没有值所以后续的MD5比较以及NacosConfigReceivedEvent
事件发布都没有走,这个时候我们就确认CachData
应该存什么值,为什么没有值
确认CachData为什么没有值问题
找到set CachData
的值代码ClientWorker.addCacheDataIfAbsent()
可以看到CacheData
主要就是存放的dataid
、gorup
等配置信息
通过
debug
发现没有走这个方法,应该是调用这个方法之前逻辑中断了,不断的向上debug
,最终找到中断执行的逻辑
解决NacosPropertySource.autoRefreshed
属性为false
因为autoRefreshed
赋值的地方有点多,就不一一说明了。我的思路就是因为配置文件是配置了nacos.config.auto-refresh=true
我们就看NacosConfigProperties.autoRefreshe
和NacosPropertySource.autoRefreshed
是否有关系;
查看
reqNacosConfig()
方法被谁调用,loadConfig()
在很多地方都有调用,我debug
的是下面方法,把nacos.config.bootstrap.log-enable=true
配置加上,就会执行loadConfig()
方法了
配置文件增加data-id
解决报错,最终缓存能实时刷新
配置文件增加nacos.config.bootstrap.log-enable=true
,执行loadConfig()
方法报错
最后在配置文件中增加
data-id
配置解决报错,实现动态刷新
总结
主要问题就是在初始化时候NacosPropertySource.autoRefreshed
属性出了问题;
有以下几种处理方式
nacos.config.data-id=jeecgBoot
nacos.config.bootstrap.enable=true
或者
nacos.config.data-id=jeecgBoot
nacos.config.bootstrap.log-enable=true
还有就是官网说的在启动类上增加一下标识并且设置autoRefeshed
@NacosPropertySource(dataId = "jeecgBoot",autoRefreshed = true)
选其中一种即可,就不要像我一样,启动类上配置dataId
,配置文件设置autoRefreshed
ps 这篇文章主要是
debug
流程,后面再梳理一篇nacos
核心执行流程文章
转载自:https://juejin.cn/post/7426282721545699337