天天看点

线上故障-java自动拆箱导致的线上NullPointerException

记录线上java自动拆箱导致的问题

2022-01-13上午发布生产,发布后观察日志发现大量的空指针异常并且监控告警,cat上查看发版后这段时间NullPointerException每分钟6000多次

线上故障-java自动拆箱导致的线上NullPointerException

赶紧回滚,由于回滚迅速未对线上造成明显影响。

接着需要排查这个异常,通过查看日志发现是PdaApiControllerd 82行报错NullPointerException

线上故障-java自动拆箱导致的线上NullPointerException
来看下这行代码
线上故障-java自动拆箱导致的线上NullPointerException

这个请求是用作校验单号的增值熟悉,从代码上分析,pdaInterceptorService是业务bean对象,肯定非null,而入参IncrementFlowRTO也不可能为null,但是奇怪了,为什么就这行报错NullPointerException,IncrementFlowRTO由于非null,那么它的三个属性为null并不会导致这行报错NullPointerException,一下子感觉有点蒙,有点违反常识了,同事还说是不是方法getIncrementType内部报的NullPointerException,如果是那样,就不会提示82行NullPointerException了。

俗话说,事出反常必有妖,肯定是哪里没理解到位。

本次是入参IncrementFlowRTO新增了字段Boolean isCheckByteDance,由于巴枪未升级,并不会上送此字段,因此解析后isCheckByteDance是null。再查看调用的方法getIncrementType的定义,如下

List<WarnBillResponse> getIncrementType(String billCode, boolean commonFlag, boolean isCheckByteDance)
           

发现入参isCheckByteDance是boolean,那么就明白了,是包装类型Boolean 自动拆箱为boolean的问题,因为null并不能转换为boolean。

同事就问了,为什么方法getIncrementType入参commonFlag是基本类型就没有这个问题呢?因为终端请求会送这个属性值,当然这个字段不会抛出NullPointerException。

这段代码是新同事写的的,直接copy前人代码然后增加自己的业务,当然别人代码写的也不规范导致他copy出现此问题,同事毕竟刚毕业工作4个月,还需要多锻炼。

这个问题虽然很小,但是很隐藏,review的时候肉眼也不容易看出。还是规范问题,统一要使用java基本数据类型对应的包装类型。

还有我们终端,对于线上终端测试同事未做兼容性测试导致,后续修改的接口,要提供给测试同事进行兼容性测试。

总结:

1.组内统一规范,不能使用java基本数据类型作为入参和出参。

2.终端要进行兼容性测试。

继续阅读