作者:shanshanhongxing | 来源:互联网 | 2023-09-16 12:36
java.lang.IllegalArgumentException:argumenttypemismatch异常背景异常容灾实现方案SpringAOP捕获接口抛出的异常
java.lang.IllegalArgumentException: argument type mismatch
异常背景
- 异常容灾
- 实现方案
- Spring AOP 捕获接口抛出的异常,保留当前类、接口、方法、入参信息
- 通过定时任务遍历当前需要重试的任务列表
- 通过反射机制重新调用接口方法
- 队列消息
- 上游应用先将数据存入DB,再发送MQ通知下游应用
- 但往往MQ的接收速度快于DB存入速度,导致下游发起查询功能时数据未录入到DB中
- 解决方案
- 时间延迟,下游应用接收到队列消息延迟5s再进行处理
- 查询重试,5s 内不断请求查询接口直到查询到数据
- 容灾重试,记录异常方法及入参,定时任务扫描重试,失败达到指定次数后邮件预警通知,手动处理
- 异常描述
- 消息内容:由于是通过消息队列传递信息,消息体为JSONObject(org.json.JSONObject)
- 存储接口:触发容灾后将接口入参转为JSON.toJSONString(底层实现为ObjectMapper) 字符串存入DB
- 反射调用:在重组参数及接口方法反射过程中程序运行正常;在Reflection.invokeMethod时出现参数不匹配异常
- 检查入参:此时检查调用方法是传入的params发现原本的org.json.JSONObject 被转为 map (LinkedHashMap) 形式
- 问题纠结
- 遇到问题时虽然检查了参数的内容,想到了与预期的JSONObject不符,但是当时在想可能就是默认的对应的映射关系
- 查询问题的重点放在了JSON工具的使用上,序列化与反序列化的工具使用,尝试换了ali的fastjson等其他工具类后发现问题依旧
异常排查
- 单元测试
- 写单元测试类只测试Reflection.invokeMethod方法,将org.json.JSONObject 转为 String ,再有 String 转回 JSONObjct 调用 Reflection.invokeMethod 方法
- 此时发生转换异常,原来的程序调用位置有多层try catch,未发现明显异常
Exception in thread “main” java.lang.ClassCastException: java.util.LinkedHashMap cannot be cast to org.json.JSONObject
- 问题定位
- org.json.JSONObject 在 toString()时转为 Map
- Map 无法逆向直接转为 org.json.JSONObject
异常解决
- 在调用Reflection.invokeMethod方法前获取参数时
- 判断如果是org.json.JSONObject.class 手动将参数Map转为JSONObject
- 问题解决
异常反思
-
认为最不可能出现问题的地方往往就是问题所在
- 发现生产环境服务访问偶尔出现丢包
- 检查各个机器节点响应,检查网络连接,查询日志
- 最终问题定位原因在于硬件故障
- 虽然一开始讨论时有人怀疑过硬件问题,但是因为这个原因发生的可能性太低了,所以一开始就被排除了
- 需要通过逐个机器停机测试的方式排查来最终定位
- 上述异常排查时只检查了Reflection.invoke方法参数入参,发现参数无误,没有仔细对照参数类型,或直接以为JSONObject与Map之间就是互逆转换,直接把排查问题的方向定位到JSON序列化的工具上,方向偏了,越走越远
-
适可而止,不要急于求成
- 不要一条道跑到黑,三十分钟没有结论,就说明要不方向错了,要不解决方案不正确,及时调整方向,避免过度纠结