Apollo 在 v0.10.0 版本後,支持自動更新。v0.10.0以前的版本在配置變化後不會從新注入,須要重啓纔會更新。數據結構
也就是說,若是一個屬性加入了 @Value 註解,而且這個配置在配置中心也存在,那麼,配置中心修改屬性值後,就會自動更新這個值。同時,有個開關能夠控制這個功能是否關閉(默認開啓)。 配置文件中寫入 apollo.autoUpdateInjectedSpringProperties = false
便可關閉該功能。框架
這次提交的 PR 詳情可見 https://codecov.io/gh/ctripcorp/apollo/pull/972/diff.post
大體先說下實現思路:spa
Apollo 實現了 BeanPostProcessor
接口,這個接口的做用則是每一個 bean 初始化成先後作操做
。設計
在 postProcessBeforeInitialization
方法中,會取出這個 Bean 的全部屬性和方法,並判斷他們是否含有 @Value
註解從而進行處理。code
具體處理邏輯,則是: 將符合條件的屬性封裝成一個 SpringValue
對象,放在一個 Map
中。當 clien
檢測到配置發生變化時,就會更新這個 Map
裏面的值,從而達到自動更新的目的。對象
固然,這只是大概的思路,具體細節則要複雜一些。接下來咱們就說說具體的實現細節。排序
相關類:接口
SpringValue
@Value 註解的詳細信息數據結構。SpringValueRegistry
@Value 註冊中心,保存了他的 key/value 機構。SpringValueDefinitionProcessor
針對 Spring 3.x 版本作的特殊操做。SpringValueProcessor
處理 @Value 註解的類。ConfigPropertySourcesProcessor
註冊 SpringValueProcessor 到容器。PropertySourcesProcessor
將 Config 和自動更新監聽器綁定,同時注入 Spring 環境。邏輯步驟:事件
不管是 XML 方式,註解方式,SpringBoot 方式,都會觸發註冊機制,即自動註冊 SpringValueProcessor
處理器到 Spring 容器(他主要是個 BeanPostProcessor
)。這是 apollo 自定義的 @Value
處理器。
不單單註冊 SpringValueProcessor
,還註冊 PropertySourcesProcessor
,這是一個 BeanFactoryPostProcessor
,即在 Spring bean 工廠初始化後,能夠進行修改的一個類。這裏的時機比 SpringValueProcessor
早。
PropertySourcesProcessor
在具體方法中,會初始化全部的 Config(ConfigService.getConfig(namespace)
),並設置到 Spring 的環境中(存儲全部的 Property,且同名狀態下優先級最高,目的是讓 Spring 本身注入到變量中)。同時,建立一個自動更新監聽器,監聽全部的 Config。
SpringValueProcessor
在容器初始化 Bean 的時候,會處理全部帶有 @Value
註解的類,並放入到 SpringValueRegistry
的 Map 中。注意:SpringValueRegistry
是單例的。而 自動更新監聽器 也是包含一個 SpringValueRegistry
的。所以,每當一個 Config 變化的時候,都會觸發 change 事件,並調用監聽器的 onChange 方法,若是匹配,該方法則會更新 SpringValueRegistry
內部的值——完成自動更新。
這裏有個問題:全部的配置都放在 SpringValueRegistry
中,一個 client 會持有多個 namespace
,每一個 namespace
可能會有重名的配置。那麼會不會發生衝突呢?實際上,apollo 考慮到了這點,在設計 namespace
的時候,就有一個 order 屬性,用於處理這種狀況,order 越小,優先級越高。當一個配置沒有顯時的設置 namespace
時,apollo 將其概括爲優先級最高的 namespace
——即 order 最小的 namespace
。而實現優先級的則是 Spring PropertySource
內部的排序機制,說白了就是一個 List,優先級最高的下標爲0,當循環匹配的時候,優先匹配下標爲0的配置。
在 shouldTriggerAutoUpdate
方法裏,有個判斷很繞:根據 key 獲取 Spring 環境中的配置值,判斷這個值和剛剛發生的變化值是否相等,若是相等,就更新 value,反之,跳過這次事件
。 解釋一下:咱們知道,@value
對應的是優先級最高的 namespace
,environment
獲取的也是優先級最高的 namespace 的配置。 若是一個配置更新了,但 environment
優先級最高的配置卻沒有更新,那麼 @value
對應的更新事件就不該該觸發。 若是一個配置更新了,environment
獲取到的優先級最高的配置也更新了,那麼 @value
對應的更新時間就應該觸發。 這裏,其實就是 @value
是否更新的重要判斷。
關於這個小功能,爲何要單獨拉出來講一說呢?實際上,該功能涉及到的東西仍是不少的。例如:
PropertySource
的 order 機制。namespace
都有一個長輪詢,發生更新後,apollo 觸發監聽器的更新事件,其中包括自動更新監聽器
,可是,須要經過 shouldTriggerAutoUpdate
的判斷才能進行更新,由於 @value 可能會和多個 namespace 重名,須要經過優先級來過濾。即:若是 Spring 環境中優先級最高的 config 更新了,那麼 @value
對應的 field 就須要更新,反之,不能更新(namespace
不匹配)。