likes
comments
collection
share

@ConfigurationProperties结合Nacos配置动态刷新之底层原理分析

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

Hello,我是大都督周瑜,本文给大家分析一下@ConfigurationProperties结合Nacos配置动态刷新的底层原理,记得点赞、关注、分享哦!

公众号:IT周瑜

应用背景

假如在Nacos中有Data ID为common.yml的配置项:

model:
  name: gpt-4

在应用的application.yml中进行导入:

spring:
  config:
    import: optional:nacos:common.yml

对应Properties类为ModelProperties

@Data
@Component
@ConfigurationProperties(prefix = "model")
public class ModelProperties {

    private String name;
}

ZhouyuService中使用ModelProperties:

@Service
public class ZhouyuService {

    @Resource
    private ModelProperties modelProperties;

    public String test() {
        return modelProperties.getName();
    }
}

直接在Nacos中进行配置修改,ZhouyuService都能及时获取到最新的配置,注意这里的用法为modelProperties.getName()

原理分析

先在ZhouyuService中进行Debug,查看配置更新前后ModelProperties对象是否是同一个对象。

配置更新前: @ConfigurationProperties结合Nacos配置动态刷新之底层原理分析

配置更新后: @ConfigurationProperties结合Nacos配置动态刷新之底层原理分析

对象是同一个,但属性值发生了变化,所以底层原理应该是:「Nacos客户端监听到配置发生了变化之后,会找到ModelProperties对象,然后调用name的set方法进行属性值的更新」

启动过程的初始化

首先,在Spring Cloud中,定义了一个ConfigurationPropertiesBeansBean对象,它有两个功能:

  1. 首先,它是一个BeanPostProcessor
  2. 其次,它里面有一个Map<String, ConfigurationPropertiesBean>类型的beans属性

@ConfigurationProperties结合Nacos配置动态刷新之底层原理分析

image.png

作为BeanPostProcessor,在它的**「初始化前」**方法中,会对Spring容器中的每个Bean对象进行判断,会过滤出那些加了@ConfigurationProperties注解的Bean,在本文中,指的就是ModelProperties对象,找到ModelProperties对象后,会把它包装为一个ConfigurationPropertiesBean对象,并存在beans这个Map中,后续配置发生变化时,会从beans中取出ModelProperties对象并进行属性值的更新。

另外,Nacos的自动配置类NacosConfigAutoConfiguration中提供了一个NacosContextRefresher的Bean对象,它是一个ApplicationListener,它监听了ApplicationReadyEvent事件: @ConfigurationProperties结合Nacos配置动态刷新之底层原理分析 在Spring Boot启动过程的最后,Spring Boot会发布ApplicationReadyEvent事件,从而触发NacosContextRefresher的事件处理逻辑,NacosContextRefresher接收到ApplicationReadyEvent事件后,会向Naocs客户端的ConfigService中注册一个Nacos配置监听器,用来监听Naocs服务端配置的改变。 @ConfigurationProperties结合Nacos配置动态刷新之底层原理分析

因此在Spring Boot启动过程中,核心会做两件事:

  1. 找到加了@ConfigurationProperties注解的Bean,并存下来
  2. 注册一个Nacos的配置监听器

配置发生变化时

一旦Nacos服务端的配置发生了变化,就会触发执行Nacos客户端的配置监听器,配置监听器会利用Spring容器发布一个RefreshEvent事件,该事件是Spring Cloud定义的。

Spring Cloud中定义了一个RefreshEventListener,就是用来处理RefreshEvent事件的: @ConfigurationProperties结合Nacos配置动态刷新之底层原理分析

而它的核心逻辑是更新Spring容器的Environment对象: @ConfigurationProperties结合Nacos配置动态刷新之底层原理分析

我们可以把Environment对象理解为Nacos服务端的配置项在客户端的本地缓存,因此Nacos客户端一旦发现服务端配置发生了改变,就会发布RefreshEvent事件,从而将Environment对象中的缓存的配置项更新为新值。

同时,在更新完Environment对象后,会再次利用Spring容器发布一个EnvironmentChangeEvent事件。

在Spring Cloud中,还定义了一个ConfigurationPropertiesRebinderBean对象: @ConfigurationProperties结合Nacos配置动态刷新之底层原理分析 它会处理EnvironmentChangeEvent事件,它会用到前面提到的ConfigurationPropertiesBeans对象,遍历它的Map中所存的那些加了@ConfigurationProperties注解的Bean: @ConfigurationProperties结合Nacos配置动态刷新之底层原理分析 比如ModelProperties对象,并针对每个Bean进行rebind()操作。

所谓rebind()操作,其实就是先从容器中获取到指定的Bean对象,也就是加了@ConfigurationProperties注解的Bean对象,先进行Bean销毁,再进行Bean初始化: @ConfigurationProperties结合Nacos配置动态刷新之底层原理分析

而Bean的初始化过程中,会执行到ConfigurationPropertiesBindingPostProcessor中的初始化前方法,会对ModelProperties对象重新进行bind: @ConfigurationProperties结合Nacos配置动态刷新之底层原理分析

而bind的过程,就是利用Environment对象中的值更新ModelProperties对象中的属性,从而完成配置的刷新,这块细节暂时就不分析了。

总结

当Nacos服务端的配置发生改变时,会触发Nacos客户端的配置监听器,从而发布RefreshEvent事件,从而更新Environment对象,从而发布EnvironmentChangeEvent事件,从而利用最新的Environment对象更新ModelProperties对象中的属性。

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