likes
comments
collection
share

Nacos如何通过RefreshScope实现配置自动更新

作者站长头像
站长
· 阅读数 19

本文主要是了解Nacos中配置更新后,如何实现配置项自动更新。

实现方式

有两种方式,使用@ConfigurationProperties注解调用get请求或者@RefreshScope + @Value这两种来实现配置的刷新。

配置属性

现象

Nacos如何通过RefreshScope实现配置自动更新

初始值是false,修改Nacos中的配置文件为true。很快配置项就变了。

Nacos如何通过RefreshScope实现配置自动更新Nacos如何通过RefreshScope实现配置自动更新

idea日志

Nacos如何通过RefreshScope实现配置自动更新

可以看到是触发了配置的更新并打印了配置变化项。

DEBUG

通过Debug知道大体流程如下:

Nacos如何通过RefreshScope实现配置自动更新

Nacos如何通过RefreshScope实现配置自动更新

配置更新的大体流程如上。NacosClient中使用了一个线程池的无线循环来监测配置的变更,即长轮询的方式去Nacos Server中去获取配置变更。

自动刷新

从上面我们可以得到配置已经更新到了Environment中,但是持有配置项的类由于已经初始化是不会变更已经设置进去的属性。容器工厂通过销毁bean,重建bean的方式来重新初始化配置对象,达到整个配置更新的操作。

配置刷新(@ConfigurationProperties)

Nacos如何通过RefreshScope实现配置自动更新

refreshEnvironment(刷新环境变量)

Nacos如何通过RefreshScope实现配置自动更新

刷新环境变量同时通过对比找出变更的配置项,再触发环境改变Event事件。

ConfigurationPropertiesRebinder(配置重新绑定)

Nacos如何通过RefreshScope实现配置自动更新

配置重新绑定类同步也实现ApplicationListener接口,监听了EnvironmentChangeEvent的改变。是通过beanFactory来销毁bean和初始化bean。

疑问?

由于Spring框架的限制,当刷新配置项时,所有的配置项都会刷新,走bean的销毁和创建过程。往往我们只需要更新其中变化的配置项即可。

Nacos如何通过RefreshScope实现配置自动更新

已经得到了变更的配置项了,结果还是刷新了所有的配置项。如果不需要进行刷新,也可以添加自定义的配置项,把对应的配置加进来即可。

Nacos如何通过RefreshScope实现配置自动更新

默认是hikari数据库连接池的datasource对象。防止刷新时造成数据库连接池重新销毁创建,造成连接的浪费。


其实我们可以通过keys想办法定位对应的配置项,在Environment中附加每一个属性对应的来源。这样可以直接通过变量操作来源进行对应的配置刷新。如果想粒度更小的话,在初始化过程中反射设置属性时,可以只设置变更的属性,最小的代价变更配置类的变量值。

单例,通过反射的方式设置配置变更项。可以通过get方式来获取变量后的值。

变量刷新(@RefreshScope + @Value)

非配置类上配置了@RefreshScope注解后,在abstractApplicationContext中实例化bean时没有走单例或者原型的初始化方式。是通过Scope的方式自定义bean的获取方式。

Nacos如何通过RefreshScope实现配置自动更新

Scope内部会维护一个数组缓存刷新对象。每次获取时从缓存内部获取对象,如果不存在则重新创建,就会重新走一遍对象的实例化,因此Value对象就会重新被赋值。

Nacos如何通过RefreshScope实现配置自动更新

Nacos如何通过RefreshScope实现配置自动更新

缓存清除

依据配置,同理可以知道也是通过event机制获取到配置更新,进而去清除缓存。我们debug一下调用栈看一下。

Nacos如何通过RefreshScope实现配置自动更新

Nacos如何通过RefreshScope实现配置自动更新

Nacos如何通过RefreshScope实现配置自动更新

最后其实就是调用了cache的clear方法,清除了所有缓存。再次获取bean时,缓存中不存在,就会重新进行创建。

疑问?

这里也是清除所有缓存,所有@RefreshScope类都会重新创建。虽然对应的配置也会更新,但是也会触发postConstruct,destory等方法,导致出现一些无法预料的问题。应用自动刷新同时也要考虑上述的情况,尽量进行规避。

总结

个人建议走配置更新的方式。通过每次使用get方法来获取到最新的变量即可。配置类没有被重新创建,开销更小,框架也是自动已经集成好了。SpringBoot中可能变量设置方式可能非常多,导致不能准确定位到变量对应的配置类,所以每次都是刷新所有的配置类和注解类,开销也很大。

转载自:https://juejin.cn/post/7282692354972123148
评论
请登录