在Tomcat应用中使用并行流带来的类加载问题
摘要
随着Java8的不断流行,越来越多的开发人员使用并行流(parallel)这一特性提升代码执行效率。但是,作者发现在Tomcat容器中使用并行流会出现动态加载类失败的情况,通过对比Tomcat多个版本的源码,结合并行流和JVM类加载机制的原理,成功定位到问题来源。本文对这个问题展开分析,并给出解决方案。
问题场景
在某应用中,服务启动时会通过并行流调用dubbo,调用代码如下:
Lists.partition(ids, BATCH_QUERY_LIMIT).stream()
.parallel()
.map(Req::new)
.map(client::batchQuery)
.collect(Collectors.toList());
调用日志中发现大量的WARN日志com.alibaba.com.caucho.hessian.io.SerializerFactory.getDeserializer Hessian/Burlap: ‘XXXXXXX’ is an unknown class in null: java.lang.ClassNotFoundException: XXXXXXX,在使用接口返回结果的时候抛出错误java.lang.ClassCastException: java.util.HashMap cannot be cast to XXXXXXX。
原因分析
初步定位
首先根据错误日志可以看到,由于依赖的dubbo服务返回参数的实体类没有找到,导致dubbo返回的数据报文在反序列化时无法转换成对应的实体,类型强制转化中报了java.lang.ClassCastException。通过对线程堆栈和WARN日志定位到出现问题的类为com.alibaba.com.caucho.hessian.io.SerializerFactory,由于 _loader 为 null 所以无法对类进行加载,相关代码如下:
try</