背景
專案配置遷移到Apollo之後,通過統一的配置管理及配置監聽使得專案配置修改的成本大大降低。
但是,在使用Apollo的過程中,強哥也遇到一個問題:如果我們要獲取Apollo下的namespace資訊需要通過ConfigServer.getConfig(String namespace)方法來獲取,但是使用這個方法的前提是我們必須知道當前專案下有哪些namespace,或者說我們只能使用我們已知的namespace。這就對我們的程式碼擴充套件性產生了限制,假如專案已經上線,而之後我們又要新增namespace或者修改已有namespace名稱,就必須更改程式碼將對應的namespace加入或修改,然後重新發布。
雖然我們不會經常修改namespace,但是,有這麼一個痛點,就讓人很不舒服。而且從官方文件中,強哥“並沒有”找到:通過專案app_id獲取到Apollo上對應的該專案下的所有namespace的方法。
那麼這個問題要怎麼解決呢?強哥今天就帶大家通過Apollo原始碼來看看如何找到解決思路。
入手點
按常理出牌,我們先在Google中搜尋一下我們的問題(這裡提一下,別用百度,他麼的根本定位不到要搜的點):
第一條搜尋結果點進去看看,是其他開發者在github上提的issue:
我們可以看到,作者的回覆是:通過open api來獲取所有namespace。也就是官方文件中的這塊內容:
額,這個……其實,官方文件中是有提到如何獲取專案下的所有namespace的方法的,那麼強哥上面為什麼說沒有找到呢?這不是啪啪啪打臉嗎?
強哥這麼說是因為官網提供的方式比較雞肋。我們可以看到,需要獲取專案下所有的namespace,需要接入Apollo開放平臺。操作步驟如下:
註冊第三方應用
給已註冊的第三方應用授權
第三方應用通過獲取的Token呼叫Apollo Open API
這尼瑪,坑爹啊,這麼麻煩,還要註冊授權拿Token才能搞,這對於強哥這種懶人來說簡直沒法接受。
Token是不可能用Token的,這輩子都不會用Token來獲取這玩意的。於是,從官方提供的Api來看是沒法了,只能另謀出路啦。
追根溯源
雖然官方文件中沒有直接提供解決問題的方法,可是我們從提供的開放平臺API倒是也可以發現一些資訊:
根據官網配置後呼叫如下:
發現確實可以獲取到專案下的所有namespace資訊,可是,資訊有點太多了,將namespace下的配置也都返回了回來,而且請求中不加入Authorization屬性的Token資訊,呼叫會返回401沒有許可權。果然強扭的瓜不甜。
那麼我們怎麼從上面的資訊找突破點呢?沒錯,如果有強哥一樣思路的同學,應該會想到:既然開放平臺提供了呼叫介面,那麼我們就去原始碼裡看看這個介面的具體實現,沒準能夠有所收穫呢!
從上圖中我們可以看到,介面地址是:http://{portal_address},那麼原始碼就從apollo-portal入手啦:
直接進到Controller目錄下(別問我為什麼知道是這個目錄,有點基礎的點開專案自然就會這麼去找了):
可以定位到我們呼叫的開放平臺的方法是這個:
程式碼很簡單,可以看到,獲取namespace走的是namespaceService.findNamespaceBOs()方法,進去實現看看(這裡為github點個贊,點選方法能夠直接跳轉到對應的實現,真的是方便):
第一行就獲取了namespace:
namespaceAPI.findNamespaceByCluster(appId, env, clusterName);
進去看看:
吼吼,原來走的也是api呼叫,可是,這個api的服務地址是哪裡呢?這就要小夥伴們對Apollo的架構有點熟悉了,上大圖:
我們呼叫的介面是Portal進去的,而底層走的是Admin Service,所以,上面程式碼的restTemplate呼叫走的就是apollo-adminservice專案啦,話不多說,進apollo-adminservice看看:
其實到這裡已經差不多了,因為再往細的研究已經沒有了意義。我們已經可以通過呼叫上圖提供的Api來獲取到我們需要的內容了,試一下:
試驗發現,確實是可以獲取到專案下的所有namespace,且不需要註冊第三方平臺應用,也不需要在呼叫介面時傳遞Authorization引數,返回的結果也剛好是簡單的所有namespace資訊。完美的解決了我們的問題。
當然有些小夥伴可能會說,這樣還是要呼叫http介面,還是有點不方便。強哥只想說,自己本地封裝一個方法,獲取應該還是比較簡單的。而且,Apollo Client提供給我們的Api,比如:ConfigService.getConfig(String namespace)其實底層也是走的socket網路呼叫,只是client為我們做了一層封裝對使用者遮蔽了而已,同時還額外加入了快取機制來提高效率。
當然,你也可以自己下載apollo-client的原始碼,然後在裡面封裝呼叫這個api的邏輯,然後maven部署到自己的私服,這樣就能和其他Api一樣呼叫啦!不過太麻煩了,強哥就不帶大家試了。
總結
先總結一下解決方法:
直接越過portal,呼叫底層admin-service的api
http://{adminservice}/apps/{appId}/clusters/{clusterName}/namespaces
{adminservice}這個地址根據自己專案配置的地址及埠去設定哦,預設埠8090~
其實,我們發現,對於開源專案,很多東西只要我們願意去找,還是能找到解決的思路的。不過,首先還是要了解其架構原理先,否則在查詢原始碼的過程中,可能會無從下手。
就拿為什麼強哥上面會知道apollo-client獲取namespace資訊的時候有使用了快取機制呢?因為強哥當時找這個問題的解決方法時,也簡單的研究了下client的原始碼,想要看看官方是否有提供對應的Api,結果沒有找到,但是也對apollo-client的部分實現有所熟悉。所以,有時候,走一些“該走的彎路”也不是壞事。
希望這篇文章對大家有用,好啦,今天就到這~
關注公眾號獲取更多內容,有問題也可在公眾號提問哦:強哥叨逼叨
叨逼叨程式設計、網際網路的見解和新鮮事