今天線上環境發現storm任務日志里有如下異常:
java.lang.NoClassDefFoundError: Could not initialize class... 某依賴工程X一個工具類方法
,
堆棧信息里找到某dubbo服務A的某方法具體某行拋出的,查看服務A的日志,也有該異常信息。
在服務A的工程里找到那行代碼,是在某個計算分支里,的確調用了工程X的一個工具類方法。
有些奇怪,因為這個工具類方法調用已上線運行很久了,以前都沒發現這個異常。
注意到該計算分支,判斷了某配置中心項的配置,僅配置了該參數的業務才會進該邏輯,查看日志發現,果然是該參數的業務才有此異常。
打開工程X的工具類方法,該工具類沒有構造函數,即使用默認的。
注意類前面有一個static Logger定義,private static Logger LOGGER = LogFactory.getLogger(XXX.class)
,該Logger是項目基礎組件封裝的,不是slf4j、common-logging等第三方包里的類;
因為static變量在類初始化時先加載,結合異常信息,那么很有可能就是這個static變量初始化失敗了。
查看git提交記錄,想起兩周前有同學改動過,對幾個記錄日志的方法內部增加了些邏輯,主要是增加記錄的字段,同時為了記錄catch中的異常,增加了這個Logger。
改動后一周左右,工程X有改動並上線。
工程X是個common包,被各個dubbo工程引用。
查看工程X的依賴,發現如下依賴順序,X->Y->Z->Logger組件。
查看服務A工程的依賴,依賴A->X並排除了Y,而A並沒有直接依賴Logger組件。
那么問題找到了,原因是服務A缺少Logger基礎組件依賴,但調用工程X工具類的static變量用到Logger基礎組件中的類。
解決方法想到兩種:
1.修改工程X該工具類,基礎組件的Logger改為用slf4j或common-logging等第三方的Logger;
2.工程X增加Logger組件的依賴。
這里想吐槽下公司的依賴管理,可以說非常混亂了:
基礎組件依賴了大量第三方組件,依賴配置的順序較混亂,有些依賴沒用上也添加了;
業務dubbo工程的依賴也較混亂,各種依賴exclude,並且配置順序較混亂。
想改變很困難,幾年下來的工程,明顯沒有代碼review,估計領導也不重視,
基礎代碼中的很多作者都不在公司了,2011、2012年的創建時間... 后來接鍋者表示╮(╯▽╰)╭
其實第1種方法要好一些,基礎組件不應該有大量依賴,但是很多其他工程在引用,改依賴風險較大;
再考慮到工程X未來可能需要基礎組件的Logger依賴,選擇了第2種方式。
總結:
遇到該異常,除了檢查異常信息中的類在依賴中是否存在,很大可能就是類里某static變量或static代碼塊,它的相關依賴類可能不存在。