StackOverflowError原因,StackOverflowError解决办法
如果你对StackOverflowError有一定的了解,就可以知道出现这个问题的主要原因就是调用栈太深,比如常见的无限递归调用。那本文要介绍的Dubbo抛出的这个StackOverflowError又是什么原因呢?且往下看。
StackOverflowError重现问题
话不多说,直入主题。这次碰到的StackOverflowError非常好重现,只需要如下简短的代码即可。需要注意的是这里调用的是
com.alibaba.dubbo.common.json.JSON,而不是fastjson中的com.alibaba.fastjson.JSON:
package com.afei.test.dubbo.provider.main; import com.alibaba.dubbo.common.json.JSON; import java.util.Locale; public class DubboTest { public static void main(String[] args) throws Exception { Locale locale = Locale.getDefault(); System.out.println(JSON.json(locale)); } }
运行这段代码能得到如下异常:
Exception in thread "main" java.lang.StackOverflowError
at java.util.concurrent.ConcurrentHashMap.get(ConcurrentHashMap.java:936)
at sun.util.locale.provider.LocaleResources.getLocaleName(LocaleResources.java:233)
at java.util.Locale.getDisplayName(Locale.java:1879)
at java.util.Locale.getDisplayName(Locale.java:1845)
at com.alibaba.dubbo.common.bytecode.Wrapper0.getPropertyValue(Wrapper0.java)
at com.alibaba.dubbo.common.json.GenericJSONConverter.writeValue(GenericJSONConverter.java:125)
at com.alibaba.dubbo.common.json.GenericJSONConverter.writeValue(GenericJSONConverter.java:73)
at com.alibaba.dubbo.common.json.GenericJSONConverter.writeValue(GenericJSONConverter.java:129)
at com.alibaba.dubbo.common.json.GenericJSONConverter.writeValue(GenericJSONConverter.java:73)
at com.alibaba.dubbo.common.json.GenericJSONConverter.writeValue(GenericJSONConverter.java:129)
at com.alibaba.dubbo.common.json.GenericJSONConverter.writeValue(GenericJSONConverter.java:73) ... ...
StackOverflowError分析原因
由这个异常堆栈信息,我们很容易知道在GenericJSONConverter中的第73行和129行之间出现了无限递归调用,打开dubbo源码并debug,发现在调用GenericJSONConverter中的writeValue()方法时,首先会判断需要序列化的对象的类型。当对象是如下类型时会特殊处理:
原生类型或者封装类型;
JSONNode类型;
枚举;
数组;
Map;
集合类型;
如果需要序列化的对象是其他类型,比如这里的Locale类型,序列化逻辑如下所示:
jb.objectBegin(); Wrapper w = Wrapper.getWrapper(c); // 得到这个对象的所有属性 String pns[] = w.getPropertyNames(); // 遍历属性 for( String pn : pns ) { // 被序列化的对象Locale并不是Throwable类型,忽略这段逻辑 if ((obj instanceof Throwable) && ( "localizedMessage".equals(pn) || "cause".equals(pn) || "stackTrace".equals(pn))) { continue; } jb.objectItem(pn); // 得到当前遍历属性的值 Object value = w.getPropertyValue(obj,pn); if( value == null || value == obj) jb.valueNull(); else // 无限递归死循环出现在这里 writeValue(value, jb, writeClass); }
通过这段源码的分析,我们大概可以知道Locale的属性中肯定有Locale类型的属性。由于有Locale类型的属性,导致继续调用GenericJSONConverter中的writeValue()方法,从而无限递归下去,让我们继续Debug源码验证这个猜想。
Debug到String pns[] = w.getPropertyNames();,我们通过查看Locale的属性pns[]可以验证我们前面的猜想,如下图所示。Locale属性availableLocales的类型还是Locale,从而出现死循环直到抛出StackOverflowError:
Locale中有Locale类型的属性
StackOverflowError解决问题
那么如何解决这个问题呢?很简单,不要使用dubbo中的JSON,改为使用fastjson中的JSON,或者jackson和GSON都可以:
Locale locale = Locale.getDefault(); System.out.println(com.alibaba.fastjson.JSON.toJSON(locale)); System.out.println(new com.google.gson.Gson().toJson(locale));
本文地址:百科问答频道 https://www.neebe.cn/wenda/903077.html,易企推百科一个免费的知识分享平台,本站部分文章来网络分享,本着互联网分享的精神,如有涉及到您的权益,请联系我们删除,谢谢!