8月
21
背景
某客户审批系统报错,界面上提示审批失败

接口没有其他错误信息,后台也没有报错,找到接口代码,代码如下:
public Map executeTaskAction(.....) throws TaskActionException { //....省略不关键代码 try { this.activitiService.executeTaskAction(iRequest, taskId, actionRequest, false); stringStringHashMap.put("success", true); return stringStringHashMap; } catch (Exception e) { stringStringHashMap.put("success", false); stringStringHashMap.put("message", "发放失败"); return stringStringHashMap; } }
从提示信息看,代码应该是抛了Exception,Exception被catch了,但是却未返回Exception的信息,也未打印Exception栈,简单说,就是Exception被吃掉了,以前碰到这种代码除了骂写代码的人傻逼外毫无办法,只能默默改了代码重新部署查看异常信息,有了Arthas后就可以在不改代码情况下查看异常信息。
排查
这次我们还是需要借助watch命令,watch命令有个参数-e
可以在方法抛出异常后进行观察,并且可以打印出异常信息,命令如下
watch com.xxx.controllers.ActivitiController executeTaskAction "{throwExp}" -e -x 2
throwExp
:异常信息- -e:如果方法异常进行观察
- -x:打印对象深度
我们观察executeTaskAction这个方法,但并没有打印异常信息,为什么呢?因为该方法已经把异常catch住了,所以不会有异常抛出,该方法如下
public Map executeTaskAction(.....) throws TaskActionException { //....省略不关键代码 try { this.activitiService.executeTaskAction(iRequest, taskId, actionRequest, false); stringStringHashMap.put("success", true); return stringStringHashMap; } catch (Exception e) { stringStringHashMap.put("success", false); stringStringHashMap.put("message", "发放失败"); return stringStringHashMap; } }
我们如果需要捕获异常,需要观察this.activitiService.executeTaskAction
方法,修改命令如下
$ watch com.xx.activiti.service.IActivitiService executeTaskAction "{throwExp}" -e -x 2 Press Q or Ctrl+C to abort. Affect(class count: 3 , method count: 2) cost in 740 ms, listenerId: 6 method=com.xx.activiti.service.impl.ActivitiServiceImpl.executeTaskAction location=AtExceptionExit ts=2021-08-04 14:33:37; [cost=155.974219ms] result=@ArrayList[ java.lang.NullPointerException at com.xx.account.service.impl.UserServiceImpl.selectDirectLeader(UserServiceImpl.java:671) at com.xx.account.service.impl.UserServiceImpl$$FastClassBySpringCGLIB$$b54795f.invoke(<generated>) at org.springframework.cglib.proxy.MethodProxy.invoke(MethodProxy.java:204) at org.springframework.aop.framework.CglibAopProxy$CglibMethodInvocation.invokeJoinpoint(CglibAopProxy.java:738) at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:157)
我们拿到异常信息是一个NullPointerException,并且出错的代码在
com.xx.account.service.impl.UserServiceImpl.selectDirectLeader(UserServiceImpl.java:671)
该方法如下
@Override public String selectDirectLeader(String jobCode) { OrgPost orgPost = orgPostMapper.selectByJobCode(jobCode); String s = userMapper.selectByJobCode(orgPost.getFatherJobCode()); if(StringUtils.isNotBlank(s)){ return s; }else { return this.selectDirectLeader(orgPost.getFatherJobCode()); } }
我们需要拿到参数去数据库中查询,才能找到空指针的具体原因,以下命令可以拿到参数值
$ watch com.hand.hap.account.service.impl.UserServiceImpl selectDirectLeader "{params[0]}" -b -x 2 ts=2021-08-04 14:39:24; [cost=0.03817ms] result=@ArrayList[ @String[00006098], ] method=com.hand.hap.account.service.impl.UserServiceImpl.selectDirectLeader location=AtEnter ts=2021-08-04 14:39:24; [cost=0.00804ms] result=@ArrayList[ @String[00006098], ]
这样拿到参数后去数据库中查询,发现有个字段维护为空,修复下数据审批恢复正常。
Address: https://zhengjianfeng.cn/?p=593
no comment untill now