怎樣檢視執行中的 Spring 應用配置?

語言: CN / TW / HK

某天,開發的程式碼在 CI 階段遇上了這樣一個看似比較「怪異」的問題:

程式碼在 CI 時,有一個步驟會跑去單元測試。因為依賴了遠端的配置中心,所以有兩份配置存在,一個在配置中心,一個是本地的 yml 檔案。這兩份配置裡使用的是兩個不同的資料庫。

一般情況下,本地開發可以方便在 yml 裡設定需要的屬性做測試,再把不同環境下的配置加到配置中心,相當於不同的 profile。

而這個怪異問題是在跑單測階段,在兩個不同的資料庫上跳來跳去,某個測試資料寫在A,其它測試可能寫在 B。

憑直覺就是配置載入的不對,但具體什麼時候使用的是哪個配置,還不確定。而 CI 的機器是個公共的容器,沒有許可權登入。

我最先想到 JMX MBean 上可能會有這些資訊。只要 JConsole 連線上去就能查看了,本地簡單試了一下,沒啥問題。

通過 org.springframework.cloud.context.environment:name=environmentManager,type=EnvironmentManager

這個 ObjectName,是可以拿到 Env 的物件,進而可以操作 setProperty 和 getProperty 的操作的,像這樣。

在操作裡可以選擇 getProperty,然後把 property 名稱寫進去點按鈕即可。

要了解JMX是啥,可以看歷史文章:

你瞭解JMX在Tomcat的應用嗎?

應用要監控,快用MBean

不過無奈遠端機器沒開放 JMX 連線,開始想其它辦法。

一番折騰之後,發現機器所在平臺上有個網頁版的命令,支援部分 Arthas 命令,可以在頁面選擇命令,輸入框裡自己定義引數值,傳送到遠端伺服器上執行。之前研究過一些 Arthas 的使用和實現原理( 阿里監控診斷工具 Arthas 原始碼原理分析 ),感覺這或許可以派上用場。畢竟 Agent 在 Attach 到 JVM 上之後,通過 JVMTI 能幹的事就太多了。

網上的文章,基本介紹都是通過 tt 的命令來實現拿到 ApplicationContext,再執行其他想要的操作。

查了下 Arthas 的文件,提供的命令裡, watch 和 tt 這兩個命令能拿到入參,返回值,target 等等,還支援 Ognl 表示式,不過前面說的頁面平臺不支援 tt,那隻能通過迂迴的使用 watch 來查看了。

折騰一番,給頁面傳送的命令加了個轉義,在 watch 中通過 target 物件再執行額外的操作,終於實現了需要的功能。

通過 watch 命令執行即可,如果你需要在本地執行,那兩個轉義符需要去掉。

org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter invokeHandlerMethod  '{target.getApplicationContext().getEnvironment().getProperty(\"app.name\"),returnObj}' -x 2

除了拿 env 裡的屬性值這種功能之外,b e s f 這幾個選項,能夠在方法執行的不同時期進行觀察,此外,也可以再增加過濾表示式,對入值增加條件,像這樣:

可以靈活組合應用在分析問題的場景中。

折騰之後,能檢視載入的配置檔案,但具體跑單測時為什麼會來回的變換配置呢? 一個同學 Debug 發現,原來是在一些測試類里加了個 @TestProperty 的註解,一些沒寫。這個註解重寫了一個配置中心 namespace 的屬性,導致拉遠端配置中心配置失敗,直接使用了本地的 yml 的配置,和 yml 配置和遠端配置中心又不一致,所以就出現了看似怪異的問題。 :-)   (:-

如果你也有需要排查的問題,可以試試 Arthas 或者相關閱讀裡的其它幾個工具。

多功能Profiling工具 JVisual VM

問題診斷神器BTrace

阿里監控診斷工具 Arthas 原始碼原理分析