這篇文章將為大家詳細(xì)講解有關(guān)Seata 中怎么動(dòng)態(tài)配置訂閱與降級(jí),文章內(nèi)容質(zhì)量較高,因此小編分享給大家做個(gè)參考,希望大家閱讀完這篇文章后對(duì)相關(guān)知識(shí)有一定的了解。
成都創(chuàng)新互聯(lián)長期為1000+客戶提供的網(wǎng)站建設(shè)服務(wù),團(tuán)隊(duì)從業(yè)經(jīng)驗(yàn)10年,關(guān)注不同地域、不同群體,并針對(duì)不同對(duì)象提供差異化的產(chǎn)品和服務(wù);打造開放共贏平臺(tái),與合作伙伴共同營造健康的互聯(lián)網(wǎng)生態(tài)環(huán)境。為南平企業(yè)提供專業(yè)的網(wǎng)站制作、網(wǎng)站建設(shè),南平網(wǎng)站改版等技術(shù)服務(wù)。擁有10年豐富建站經(jīng)驗(yàn)和眾多成功案例,為您定制開發(fā)。
Seata 配置中心有一個(gè)監(jiān)聽器基準(zhǔn)接口,它主要有一個(gè)抽象方法和 default 方法,如下:
io.seata.config.ConfigurationChangeListener
該監(jiān)聽器基準(zhǔn)接口主要有兩個(gè)實(shí)現(xiàn)類型:
實(shí)現(xiàn)注冊(cè)配置訂閱事件監(jiān)聽器:用于實(shí)現(xiàn)各種功能的動(dòng)態(tài)配置訂閱,比如 GlobalTransactionalInterceptor 實(shí)現(xiàn)了 ConfigurationChangeListener,根據(jù)動(dòng)態(tài)配置訂閱實(shí)現(xiàn)的動(dòng)態(tài)降級(jí)功能;
實(shí)現(xiàn)配置中心動(dòng)態(tài)訂閱功能與適配:對(duì)于目前還沒有動(dòng)態(tài)訂閱功能的 file 類型默認(rèn)配置中心,可以實(shí)現(xiàn)該基準(zhǔn)接口來實(shí)現(xiàn)動(dòng)態(tài)配置訂閱功能;對(duì)于阻塞訂閱需要另起一個(gè)線程去執(zhí)行,這時(shí)候可以實(shí)現(xiàn)該基準(zhǔn)接口進(jìn)行適配,還可以復(fù)用該基準(zhǔn)接口的線程池;以及還有異步訂閱,有訂閱單個(gè) key,有訂閱多個(gè) key 等等,我們都可以實(shí)現(xiàn)該基準(zhǔn)接口以適配各個(gè)配置中心。
這里就用默認(rèn)的 file 配置中心,以它的實(shí)現(xiàn)類 FileListener 舉例子,它的實(shí)現(xiàn)邏輯如下:
如上,
dataId:為訂閱的配置屬性;
listener:配置訂閱事件監(jiān)聽器,用于將外部傳入的 listener 作為一個(gè) wrapper,執(zhí)行真正的變更邏輯,這里特別需要注意的是,該監(jiān)聽器與 FileListener 同樣實(shí)現(xiàn)了 ConfigurationChangeListener 接口,只不過 FileListener 是用于給 file 提供動(dòng)態(tài)配置訂閱功能,而 listener 用于執(zhí)行配置訂閱事件;
executor:用于處理配置變更邏輯的線程池,在 ConfigurationChangeListener#onProcessEvent 方法中用到。
FileListener#onChangeEvent 方法的實(shí)現(xiàn)讓 file 具備了動(dòng)態(tài)配置訂閱的功能,它的邏輯如下:
無限循環(huán)獲取訂閱的配置屬性當(dāng)前的值,從緩存中獲取舊的值,判斷是否有變更,如果有變更就執(zhí)行外部傳入 listener 的邏輯。
ConfigurationChangeEvent 用于保存配置變更的事件類,它的成員屬性如下:
這里的 getConfig 方法是如何感知 file 配置的變更呢?我們點(diǎn)進(jìn)去,發(fā)現(xiàn)它最終的邏輯如下:
發(fā)現(xiàn)它是創(chuàng)建一個(gè) future 類,然后包裝成一個(gè) Runnable 放入線程池中異步執(zhí)行,最后調(diào)用 get 方法阻塞獲取值,那么我們繼續(xù)往下看:
allowDynamicRefresh:動(dòng)態(tài)刷新配置開關(guān);
targetFileLastModified:file 最后更改的時(shí)間緩存。
以上邏輯:
獲取 file 最后更新的時(shí)間值 tempLastModified,然后對(duì)比對(duì)比緩存值 targetFileLastModified,如果 tempLastModified > targetFileLastModified,說明期間配置有更改過,這時(shí)就重新加載 file 實(shí)例,替換掉舊的 fileConfig,使得后面的操作能夠獲取到最新的配置值。
添加一個(gè)配置屬性監(jiān)聽器的邏輯如下:
configListenersMap 為 FileConfiguration 的配置監(jiān)聽器緩存,它的數(shù)據(jù)結(jié)構(gòu)如下:
ConcurrentMap> configListenersMap
從數(shù)據(jù)結(jié)構(gòu)上可看出,每個(gè)配置屬性可關(guān)聯(lián)多個(gè)事件監(jiān)聽器。
最終執(zhí)行 onProcessEvent 方法,這個(gè)是監(jiān)聽器基準(zhǔn)接口里面的 default 方法,它會(huì)調(diào)用 onChangeEvent 方法,即最終會(huì)調(diào)用 FileListener 中的實(shí)現(xiàn)。
有了以上的動(dòng)態(tài)配置訂閱功能,我們只需要實(shí)現(xiàn) ConfigurationChangeListener 監(jiān)聽器,就可以做各種各種的功能,目前 Seata 只有動(dòng)態(tài)降級(jí)有用到動(dòng)態(tài)配置訂閱的功能。
在「Seata AT 模式啟動(dòng)源碼分析」這篇文章中講到,Spring 集成 Seata 的項(xiàng)目中,在 AT 模式啟動(dòng)時(shí),會(huì)用 用GlobalTransactionalInterceptor 代替了被 GlobalTransactional 和 GlobalLock 注解的方法,GlobalTransactionalInterceptor 實(shí)現(xiàn)了 MethodInterceptor,最終會(huì)執(zhí)行 invoker 方法,那么想要實(shí)現(xiàn)動(dòng)態(tài)降級(jí),就可以在這里做手腳。
在 GlobalTransactionalInterceptor 中加入一個(gè)成員變量:
private volatile boolean disable;
在構(gòu)造函數(shù)中進(jìn)行初始化賦值:
ConfigurationKeys.DISABLE_GLOBAL_TRANSACTION(service.disableGlobalTransaction)這個(gè)參數(shù)目前有兩個(gè)功能:
在啟動(dòng)時(shí)決定是否開啟全局事務(wù);
在開啟全局事務(wù)后,決定是否降級(jí)。
實(shí)現(xiàn) ConfigurationChangeListener:
這里的邏輯簡(jiǎn)單,就是判斷監(jiān)聽事件是否屬于 ConfigurationKeys.DISABLE_GLOBAL_TRANSACTION 配置屬性,如果是,直接更新 disable 值。
接下來在 GlobalTransactionalInterceptor#invoke 中做點(diǎn)手腳
如上,disable = true 時(shí),不執(zhí)行全局事務(wù)與全局鎖。
配置中心訂閱降級(jí)監(jiān)聽器
io.seata.spring.annotation.GlobalTransactionScanner#wrapIfNecessary
關(guān)于Seata 中怎么動(dòng)態(tài)配置訂閱與降級(jí)就分享到這里了,希望以上內(nèi)容可以對(duì)大家有一定的幫助,可以學(xué)到更多知識(shí)。如果覺得文章不錯(cuò),可以把它分享出去讓更多的人看到。