Spring Cloud Config動(dòng)態(tài)配置是如何實(shí)現(xiàn)的贱勃?
一刚操,配置中心動(dòng)態(tài)配置概述
Spring Cloud Config的動(dòng)態(tài)配置需要借助Spring Cloud Bus來實(shí)現(xiàn)。如何實(shí)現(xiàn)的呢伶椿?我們先來看看思路:Spring Cloud Bus對(duì)外提供一個(gè)http接口辜伟,我們將這個(gè)接口配置到git上。當(dāng)git上的文件內(nèi)容發(fā)生變化時(shí)脊另,就會(huì)自動(dòng)調(diào)用我們定義的這個(gè)接口导狡,然后Config Server就會(huì)重新從git獲取最新的配置信息。Config Server把最新的配置信息放到消息隊(duì)列中偎痛,Config Client訂閱該消息旱捧,這樣就實(shí)現(xiàn)了動(dòng)態(tài)刷新配置信息的功能。
二踩麦,@RefreshScope注解
關(guān)于這個(gè)注解枚赡,官方是這樣解釋的:
Note that all beans in this scope are only initialized when first accessed, so the scope forces lazy initialization semantics.? The implementation involves creating a proxy for every bean in the scope, so there is a flag.
If a bean is refreshed then the next time the bean is accessed a new instance is created.? All lifecycle methods are applied to the bean instances, so any destruction callbacks that were registered in the bean factory are called when it is refreshed, and then the initialization callbacks are invoked as normal when the new instance is created. A new bean instance is created from the original bean definition, so any externalized content is re-evaluated when it is created.
這段話我就不再翻譯了氓癌,原滋原味的,多讀幾遍标锄,更能體會(huì)坐著作者的原意顽铸。實(shí)在不懂得茁计,可以去使用瀏覽器搜索翻譯一下料皇。我們來看作者的代碼是怎么寫的。
@RefreshScope注解的處理類是RefreshScope.class星压,具體的刷新邏輯就是
RefreshScope.refresh(name)和RefreshScope.refreshAll()践剂。
大致思路是這樣的:拿到@RefreshScope注解的bean,清空bean緩存娜膘,這樣下次執(zhí)行bean時(shí)逊脯,就會(huì)重新生成bean了,這樣就實(shí)現(xiàn)了這個(gè)bean下面的所有配置信息的自動(dòng)刷新了竣贪。
注意這里的bean緩存是:
GenericScope.BeanLifecycleWrapperCache
并且在父類GenericScope中军洼,還會(huì)對(duì)外暴露一個(gè)接口/refresh,修改配置以后演怎,我們只要手動(dòng)訪問一下這個(gè)接口 就可以實(shí)現(xiàn)刷新配置的功能了匕争。
調(diào)用RefreshScope的地方在哪里呢?
在這里:ContextRefresher.refresh()
源碼如下:
// 判斷PropertySource的實(shí)現(xiàn)是否是
// EnumerablePropertySource爷耀,如果是甘桑,則
//加入result并返回。
Map<String, Object> before = this.extract(this.context.getEnvironment().getPropertySources());
// 重新獲取配置文件
this.addConfigFilesToEnvironment();
// 比較配置文件更新前后歹叮,找出變更的那一部分配置
Set<String> keys = this.changes(before, this.extract(this.context.getEnvironment().getPropertySources())).keySet();
// 發(fā)布環(huán)境變更事件
this.context.publishEvent(new EnvironmentChangeEvent(keys));
// 開啟定時(shí)任務(wù)
this.scope.refreshAll();
// 把變更的配置的key組成的集合返回
return keys;
總結(jié):@RefreshScope注解是如何實(shí)現(xiàn)自動(dòng)刷新bean配置信息的呢跑杭?說白了,就是讓bean失效咆耿,這樣下次訪問bean時(shí)德谅,就會(huì)重新生成bean了。
但是萨螺,這里窄做,我還有一個(gè)疑問:如果修改配置后,不去手動(dòng)訪問spring暴露的/refresh接口屑迂,下次訪問@RefreshScope注解的bean時(shí)浸策,能獲取到最新的配置信息嗎?
三惹盼,Spring Cloud Bus
什么是Spring Cloud Bus:輕量級(jí)的消息代理庸汗。從技術(shù)角度來說,Spring Cloud Bus使用了java的事件處理機(jī)制和MQ的部分特性手报。
Spring Cloud Bus的工作流程:
發(fā)送端:構(gòu)造事件event蚯舱,將其publish到applicationContext中改化,然后將事件發(fā)布到channel。
接收端:從channel中獲取message枉昏,將message轉(zhuǎn)為event陈肛,然后將event事件publish到applicationContext中,最后接收端收到event兄裂,調(diào)用服務(wù)進(jìn)行邏輯處理句旱。
publish:這里的publish是ApplicationEventPublisher
channel:這里的channel是MessageChannel
event:ApplicationEvent,具體實(shí)現(xiàn)有以下幾種:
AckRemoteApplicationEvent
RefreshRemoteApplicationEvent
UnknownRemoteApplicationEvent
EnvironmentChangeRemoteApplicationEvent
具體的細(xì)節(jié)這里不再贅述晰奖,會(huì)另起文章討論
Spring Cloud Bus谈撒,這里明白大概流程即可。
四匾南,Git 之 WebHooks
什么是Webhooks呢啃匿?官方解釋如下:
Webhooks allow external services to be notified when certain events happen. When the specified events happen, we’ll send a POST request to each of the URLs you provide.
翻譯過來就是:
Webhooks允許在某些事件發(fā)生時(shí)通知外部服務(wù)。當(dāng)指定的事件發(fā)生時(shí)蛆楞,我們將向您提供的每個(gè)URLs發(fā)送一個(gè)POST請(qǐng)求溯乒。
借助Webhooks,我們就可以在git遠(yuǎn)程倉庫的配置發(fā)生變化時(shí)豹爹,讓git通知Config Server裆悄,從而實(shí)現(xiàn)自動(dòng)刷新的功能。