如果让你设计一个动态配置的功能,你会怎么做?注意是动态配置,不是配置中心。
先在大脑里面考虑3分钟,也许你有答案了。
对的,你肯定想的和下面一样:
上图是需要人工发起通知的动态配置架构,实现很简单。
但我们为什么要人工操作两次呢,可不可以简化到一次?
对于上图只需要稍作调整,就能达到只需要一次修改配置文件操作。
这样看起来简单多了。
采用定时任务,可以减少人工操作次数,但同时带来了一定的性能损耗。
回到nacos,它多采用的模型是定时任务来获取配置文件。
如果是一台机器,一个配置文件,上面的架构似乎完美胜任,如果将应用变成n个,机器n台,配置文件n个,
此时就会存在问题,人工操作不可能完成上面的工作,也容易出错。必须要自动化才能既保证效率提高,还
能保证不出错。
对此,只需要将上面的架构稍微改一改,就能满足需求。
nacos就是以上架构,十分的简单。
现在来看下他是如何集成到SpringCloud里面取得。
先来了解SpringBoot/SpringCloud中几个关键类。
MapPropertySource<T>:这个是spring中属性配置的数据源,所有的配置文件都要转成这样的形式。
RefreshEvent:发送该事件,可以类似调用RefreshEndpoint#refresh,也就是通知spring刷新配置文件。
EnvironmentChangeEvent:发送该事件,会通知环境已经发生变化。
ContextRefresher:刷新管理类。
NacosContextRefresher:nacos配置上下文管理类。
RefreshScope:该注解会把bean加入到'refresh'的scope中。
ClientWorker:nacos配置中心客户端,会定时http请求服务器。
其通信图如下:
1.在nacos上修改配置。
2.nacos客户端中ClientWorker会每隔10ms异步读取一次配置中心文件md5值。
3.和本地md5值比较,有变化的从服务器拉取。
4.将文件保存/缓存到本地。
5.通知NacosContextRefresher配置文件有变化。
6.NacosContextRefresher判断是否需要更新配置。
7.发送事件通知ContextRefresher去更新。
8.这里是更新配置的关键步骤。
9.准备一份before配置,然后通过构建新的Environment的方式拿到新的配置, 接着比较变化,得到有变化的keys。
10.构建Environment时会去读取配置文件,文件优先读本地,如果本地没有通过Http请求服务商。
11.构建NacosPropertiesSource,并重新生成ConfigurationProperties对象。
12.通知RefreshScope去更新。
13.销毁scope='refresh'的bean。
14.通知bean容器去构建新的bean(懒加载)。
15.将属性(@Value注解)注入到新的bean。