本文場景基于dubbo-2.5.3版本。
如果你對StackOverflowError有一定的了解,就可以知道出現這個問題的主要原因就是調用棧太深,比如常見的無限遞歸調用。那本文要介紹的Dubbo拋出的這個StackOverflowError又是什么原因呢?且往下看。
重現問題
話不多說,直入主題。這次碰到的StackOverflowError非常好重現,只需要如下簡短的代碼即可。需要注意的是這里調用的是com.alibaba.dubbo.common.json.JSON,而不是fastjson中的com.alibaba.fastjson.JSON:
Dubbo還有這樣的bug,你能忍?
運行這段代碼能得到如下異常:
Dubbo還有這樣的bug,你能忍?
分析原因
由這個異常堆棧信息,我們很容易知道在GenericJSONConverter中的第73行和129行之間出現了無限遞歸調用,打開dubbo源碼并debug,發現在調用GenericJSONConverter中的writeValue()方法時,首先會判斷需要序列化的對象的類型。當對象是如下類型時會特殊處理:
原生類型或者封裝類型;
JSONNode類型;
枚舉;
數組;
Map;
集合類型;
如果需要序列化的對象是其他類型,比如這里的Locale類型,序列化邏輯如下所示:
Dubbo還有這樣的bug,你能忍?
通過這段源碼的分析,我們大概可以知道Locale的屬性中肯定有Locale類型的屬性。由于有Locale類型的屬性,導致繼續調用GenericJSONConverter中的writeValue()方法,從而無限遞歸下去,讓我們繼續Debug源碼驗證這個猜想。
Debug到String pns[] = w.getPropertyNames();,我們通過查看Locale的屬性pns[]可以驗證我們前面的猜想,如下圖所示。Locale屬性availableLocales的類型還是Locale,從而出現死循環直到拋出StackOverflowError:
Dubbo還有這樣的bug,你能忍?
解決問題
那么如何解決這個問題呢?很簡單,不要使用dubbo中的JSON,改為使用fastjson中的JSON,或者jackson和GSON都可以:
Dubbo Fix
筆者翻看dubbo issue歷史,發現dubbo在2018-05-09修復了這個問題,對應的dubbo版本是2.6.3,描述為:add Locale serialize & deserialize support。pull地址如下:https://github.com/apache/dubbo/pull/1761/commits。
修復的代碼片段如下所示,主要改動點有:
如果序列化對象是Locale類型,那么序列化方式就是調用toString()方法;
如果反序列化目標對象類型是Locale,那么將value以下劃線分割,然后構造Locale對象,用法參考:JSON.parse("zhCN", Locale.class);
Dubbo還有這樣的bug,你能忍?
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。