最近碰到一個問題,把解決的過程記錄下來。
同僚的應用上線,tomcat無法正常啟動。抛出這樣的異常:
據同僚說,線上下環境,可以正常運作,線上上環境就出錯了,非常的詭異。
程式有一個env.properties的配置檔案:
broker.producer = failover://(nio://10.0.0.3:91615?connectiontimeout=3000,nio://10.0.0.4:91615?connectiontimeout=3000)
線上和線下加載的是不同的env.properties。
在spring xml配置檔案裡有這樣的配置:
spring在運作時,會自動替換${}表達式裡的值。
線上上機器上,執行
telnet 10.0.0.3 91616
可以正常連接配接,再到activemq的web console上檢視connection,發現的确沒有這個ip的連接配接。
線上的配置的brokeruri是這個:
failover://(nio://10.0.0.3:91616?connectiontimeout=3000,nio://10.0.0.4:91616?connectiontimeout=3000)
直接先改為最簡單的,在vim下yy複制了一行,删除多餘的,剩下:
nio://10.0.0.3:91616
發現還是報異常。
在本地跑了個簡單程式,用xshell的端口轉發,把本地請求轉發到線上機器上,發現可以正常發送消息。于是讓同僚回去檢查代碼裡的其它問題了。
但是同僚沒有找到錯誤,于是把剛才的簡單的程式打成一個fat jar包,放到線上機器上去跑,發現可以正常發送activemq消息。
程式打包用的是maven的one jar 插件,參考:
http://www.mkyong.com/maven/maven-create-a-fat-jar-file-one-jar-example/
把測試程式放到同僚的war包的代碼裡,放到線上機器,發現可以正常發送消息。
但是同僚配置的activemq還是不能發送消息,還是報“invalid broker uri”異常。
沒辦法了,把同僚的環境變量${broker.producer},設定到測試代碼裡,發現測試代碼抛異常了。
于是确認是${broker.producer} 這個變量有問題。
但是env.properties檔案裡的配置看起來是對的。于是懷疑是配置檔案格式有問題。
備份舊檔案,建了個新配置檔案,配置上
broker.producer =nio://10.0.0.3:91615
發現,居然正常了。
于是對比兩個配置檔案,發現舊的配置檔案上,最後多了一個空格。。就是91615後面多了一個空格。
蛋疼無比,activemq居然不能識别處理配置值後面多出來的一個空格。而且spring抛出來的異常裡也沒有這個資訊。
開始調試時,找不到原始的異常資訊在哪裡,spring的函數調用層次太多了。于是采用代碼搜尋。
在 https://searchcode.com 搜尋"invalid broker uri",終于找到原始的異常資訊是下面的代碼抛出來的:
很奇怪的是,illegalargumentexception異常裡是正确地把urisyntaxexception設定到cause裡了,後面的spring卻沒有把這個資訊給列印出來。。
為什麼spring能把前面的異常資訊都列印出來,而原始的異常資訊卻不能列印出來?比如某個spring異常資訊是這樣的:
caused by: org.springframework.beans.propertybatchupdateexception; nested propertyaccessexceptions (1) are:
srping會用caused by,nested exception is,這樣的字元把所有的異常都串起來。到底這裡面是怎麼工作的?
再次搜尋"nested exception is"
查找到spring相關的代碼。
原來所有的spring異常類都繼承自nestedruntimeexception,而nestedruntimeexception重寫了getmessage()函數,在getmessage()函數裡,會把異常的資訊全都串起來。
而illegalargumentexception繼承自throwable類,throwable類的getmessage()函數隻是簡單列印了message,并沒有把cause也輸出。
nestedexceptionutils這個類是abstract,這樣可以防止使用者得到執行個體,這樣使用者不能用錯。這個也是一個常見的util類的技巧了。
這個代碼搜尋網站比較好用:https://searchcode.com
很多流行網站的資料都有,比github上要全。
後來在網上搜尋了下“invalid broker uri”,有10萬多條結果。。估計有不少就是因為一些空格而造成的。。
activemq的開發者隻需要加上一點點的trim()的判斷處理代碼,就可以減少很多人的痛苦了。
是以防禦性程式設計還是有必要的,有的時候并不真的是使用者不會用,而是錯誤來自想像不到的地方。