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

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对象是否是同一个对象。

配置更新前:
image.png

配置更新后:
image.png

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

启动过程的初始化

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

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

image.png

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

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

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

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

配置发生变化时

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

Spring Cloud中定义了一个RefreshEventListener,就是用来处理RefreshEvent事件的:
image.png

而它的核心逻辑是更新Spring容器的Environment对象:
image.png

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

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

在Spring Cloud中,还定义了一个ConfigurationPropertiesRebinderBean对象:
image.png
它会处理EnvironmentChangeEvent事件,它会用到前面提到的ConfigurationPropertiesBeans对象,遍历它的Map中所存的那些加了@ConfigurationProperties注解的Bean:
image.png
比如ModelProperties对象,并针对每个Bean进行rebind()操作。

所谓rebind()操作,其实就是先从容器中获取到指定的Bean对象,也就是加了@ConfigurationProperties注解的Bean对象,先进行Bean销毁,再进行Bean初始化:
image.png

而Bean的初始化过程中,会执行到ConfigurationPropertiesBindingPostProcessor中的初始化前方法,会对ModelProperties对象重新进行bind:
image.png

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

总结

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

@ConfigurationProperties是Spring Boot中用于读取配置文件的注解,它可以将配置文件中的属性值映射到对应的Java类中的属性上。在Nacos配置中,可以使用@ConfigurationProperties注解来读取Nacos配置。 @ConfigurationProperties注解可以与@Value注解一起使用。@Value注解用于直接注入配置文件中的属性值,而@ConfigurationProperties注解可以将整个配置文件的属性值映射到一个Java类中。在使用@ConfigurationProperties注解时,需要在类上加上@Component或@Configuration注解,并通过prefix属性指定要读取的配置文件的前缀。 在使用Nacos作为配置中心时,可以使用@ConfigurationProperties注解来读取Nacos配置。通过在@ConfigurationProperties注解的prefix属性中指定Nacos配置的前缀,即可将Nacos配置映射到对应的Java类中的属性上。 例如,可以创建一个名为NacosConfig的Java类,并使用@ConfigurationProperties注解来读取Nacos配置。代码示例如下: ```java @Component @ConfigurationProperties(prefix = "nacos") public class NacosConfig { private String server; private String username; private String password; // 省略getter和setter方法 } ``` 在上述代码中,通过@ConfigurationProperties注解和prefix属性指定了Nacos配置的前缀为"nacos",并将Nacos配置中的server、username和password属性映射到了NacosConfig类的对应属性上。 使用@ConfigurationProperties注解读取Nacos配置后,可以通过依赖注入的方式将NacosConfig类注入到其他需要使用Nacos配置的类中,并直接使用对应的属性值。 总结起来,@ConfigurationProperties注解可以与Nacos配置一起使用,将Nacos配置映射到对应的Java类中的属性上,方便在程序中使用Nacos配置。<span class="em">1</span><span class="em">2</span><span class="em">3</span> #### 引用[.reference_title] - *1* *3* [程序中读取Nacos配置信息](https://blog.csdn.net/weixin_44946168/article/details/122346390)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_1"}}] [.reference_item style="max-width: 50%"] - *2* [使用Spring的@Value和@ConfigurationPropertiesNacos或yml中获取值并自动刷新](https://blog.csdn.net/jike11231/article/details/122866973)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_1"}}] [.reference_item style="max-width: 50%"] [ .reference_list ]
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值