生产中静态块造成Json日期解析失败定位方法

生产上错误显示

今天同事过来找我,给我发了一个生产故障如下:

`08-May-2020 18:10:53.862 SEVERE [http-nio-8080-exec-327] org.apache.catalina.core.StandardWrapperValve.invoke Servlet.service() for servlet [springmvc] in context with path [] threw exception [Request processing failed; nested exception is net.sf.json.JSONException: Error while setting property=effectdate type class java.lang.String] with root cause
 net.sf.ezmorph.MorphException: Unable to parse the date 2020-04-21 00:00:00
        at net.sf.ezmorph.object.DateMorpher.morph(DateMorpher.java:211)
        at net.sf.ezmorph.MorpherRegistry.morph(MorpherRegistry.java:167)
        at net.sf.json.JSONObject.morphPropertyValue(JSONObject.java:1381)
        at net.sf.json.JSONObject.toBean(JSONObject.java:363)
        at net.sf.json.JSONObject.toBean(JSONObject.java:233)`

说很奇怪,灰度和测试环境一直没出现这个报错,生产上有。带着他的疑问,我开始了故障排查。

net.sf.ezmorph.MorphException: Unable to parse the date 2020-04-21 00:00:00

这个报错,是因为无法解析这个日期格式导致的,解决方案如下:

//注册一个DateMorpher类,来处理对应的日期格式
MorpherRegistry mr = JSONUtils.getMorpherRegistry();
DateMorpher dm = new DateMorpher(new String[] { "YYYY_MM_DD",
      "YYYY_MM_DD_HH_MM_ss", "HH_MM_ss", "YYYYMMDD",
      "YYYYMMDDHHMMSS", "HHMMss", "yyyy-MM-dd HH:mm:ss" });
mr.registerMorpher(dm);

但是我们不是需要解决这么bug,而是我们要定位,为什么生产会有bug,而测试和灰度环境没有。

好了,现在我们开始描述下,我的分析方法。

故障重现

首先我们对比下生产和测试代码执行的监控,我这边给大家推荐一款神器:arthas

通过arthas来监控报错代码运行状态:

我们去到生产环境,报错代码方法是morph方法:

net.sf.ezmorph.object.DateMorpher.morph(DateMorpher.java:211)

我们利用

trace net.sf.ezmorph.object.DateMorpher morph
在这里插入图片描述

提示No class or method is affected,表示DateMorpher这个类是通过ClassLoader加载的。

我们看下源码,可以得知,这个DateMorpher,是通过ClassLoader加载,导致通过arthas无法得到增强。

生产中静态块造成Json日期解析失败定位方法_第1张图片

下一步,我们可以通过watch命令,看下net.sf.ezmorph.MorpherRegistry.morph 方法return的值是什么

生产环境:
net.sf.ezmorph.MorpherRegistry morph "{returnObj}" -x 2

Press Q or Ctrl+C to abort.
Affect(class-cnt:1 , method-cnt:1) cost in 105 ms.

ts=2020-05-17 14:22:23; [cost=0.355289ms] result=@ArrayList[
    @Date[2020-05-17 14:22:23,551],
]

测试和演练环境:
net.sf.ezmorph.MorpherRegistry morph "{returnObj}" -x 2

Press Q or Ctrl+C to abort.
Affect(class-cnt:1 , method-cnt:1) cost in 105 ms.
ts=2020-05-17 14:22:23; [cost=0.039714ms] result=@ArrayList[
    @String[0],
]

咱们可以发现,测试环境并没有初始化DateMorpher这个对象,测试环境默认使用的是BeanMorpher这个对象,来进行数据的转换,而BeanMorpher对任意日期格式处理,是不会产生报错。

再回到生产环境的DateMorpher这个源码中,发现报错就是由于我们没有设置日期格式导致。

生产中静态块造成Json日期解析失败定位方法_第2张图片

总结:测试环境没有初始化DateMorpher对象,来对响应的日期进行处理,导致测试环境不会报错。而生产加载了DateMorpher对象。

最终解决

生产中静态块造成Json日期解析失败定位方法_第3张图片
我们在代码中搜索DateMorpher,发现如下代码

而并没有定义yyyy-MM-dd HH:mm:ss格式日期,导致最终报错。而这个类是静态块,只有类被调用时候才会执行,生产上由于用户执行某个功能导致这个静态快被执行,而测试环境代码覆盖了部分功能,不会执行这个静态块。

你可能感兴趣的:(java)