暂无图片
暂无图片
暂无图片
暂无图片
暂无图片

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

IT周瑜 2024-05-28
281

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

应用背景

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

配置更新前:

配置更新后:

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

启动过程的初始化

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

  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
事件:在Spring Boot启动过程的最后,Spring Boot会发布ApplicationReadyEvent
事件,从而触发NacosContextRefresher
的事件处理逻辑,NacosContextRefresher
接收到ApplicationReadyEvent
事件后,会向Naocs客户端的ConfigService
中注册一个Nacos配置监听器,用来监听Naocs服务端配置的改变。

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

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

配置发生变化时

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

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

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

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

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

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

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

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

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

总结

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

小广告

一直在公司边做架构、边做AI大模型相关的开发工作,所以顺带出一个AI课程,课程包含了LangChain、SpringAI、RAG、文本向量化、图片向量化、文搜图、图搜图、文生文、文生图、Tools机制、智能体Agent、多智能体Multi-Agent、大模型私有化部署、大模型微调、Llama3、GPT-4o、知识图谱、智能体编排...等等目前主流的大模型技术,即讲了应用实战,又讲了原理源码,话说我是不是第一个讲大模型相关源码的?

这些技术足够你成为大模型应用开发工程师了,足够你在领导和面试官面前炫技了,课程都是我讲的,全程干货,学过的都说好,关键性价比还高,感兴趣的可以加我微信私聊,备注:大都督AI


文章转载自IT周瑜,如果涉嫌侵权,请发送邮件至:contact@modb.pro进行举报,并提供相关证据,一经查实,墨天轮将立刻删除相关内容。

评论