Reflection.invokeMethod argument type mismatch

java.lang.IllegalArgumentException: argument type mismatch


異常背景

  1. 異常容災
    1. 實現方案
      1. Spring AOP 捕獲接口拋出的異常,保留當前類、接口、方法、入參信息
      2. 通過定時任務遍歷當前需要重試的任務列表
      3. 通過反射機制重新調用接口方法
  2. 隊列消息
    1. 上游應用先將數據存入DB,再發送MQ通知下游應用
    2. 但往往MQ的接收速度快於DB存入速度,導致下游發起查詢功能時數據未錄入到DB中
    3. 解決方案
      1. 時間延遲,下游應用接收到隊列消息延遲5s再進行處理
      2. 查詢重試,5s 內不斷請求查詢接口直到查詢到數據
      3. 容災重試,記錄異常方法及入參,定時任務掃描重試,失敗達到指定次數後郵件預警通知,手動處理
  3. 異常描述
    1. 消息內容:由於是通過消息隊列傳遞信息,消息體爲JSONObject(org.json.JSONObject)
    2. 存儲接口:觸發容災後將接口入參轉爲JSON.toJSONString(底層實現爲ObjectMapper) 字符串存入DB
    3. 反射調用:在重組參數及接口方法反射過程中程序運行正常;在Reflection.invokeMethod時出現參數不匹配異常
    4. 檢查入參:此時檢查調用方法是傳入的params發現原本的org.json.JSONObject 被轉爲 map (LinkedHashMap) 形式
  4. 問題糾結
    1. 遇到問題時雖然檢查了參數的內容,想到了與預期的JSONObject不符,但是當時在想可能就是默認的對應的映射關係
    2. 查詢問題的重點放在了JSON工具的使用上,序列化與反序列化的工具使用,嘗試換了ali的fastjson等其他工具類後發現問題依舊

異常排查

  1. 單元測試
    1. 寫單元測試類只測試Reflection.invokeMethod方法,將org.json.JSONObject 轉爲 String ,再有 String 轉回 JSONObjct 調用 Reflection.invokeMethod 方法
    2. 此時發生轉換異常,原來的程序調用位置有多層try catch,未發現明顯異常

Exception in thread “main” java.lang.ClassCastException: java.util.LinkedHashMap cannot be cast to org.json.JSONObject

  1. 問題定位
    1. org.json.JSONObject 在 toString()時轉爲 Map
    2. Map 無法逆向直接轉爲 org.json.JSONObject

異常解決

  1. 在調用Reflection.invokeMethod方法前獲取參數時
  2. 判斷如果是org.json.JSONObject.class 手動將參數Map轉爲JSONObject
  3. 問題解決

異常反思

  1. 認爲最不可能出現問題的地方往往就是問題所在

    1. 發現生產環境服務訪問偶爾出現丟包
      1. 檢查各個機器節點響應,檢查網絡連接,查詢日誌
      2. 最終問題定位原因在於硬件故障
      3. 雖然一開始討論時有人懷疑過硬件問題,但是因爲這個原因發生的可能性太低了,所以一開始就被排除了
      4. 需要通過逐個機器停機測試的方式排查來最終定位
    2. 上述異常排查時只檢查了Reflection.invoke方法參數入參,發現參數無誤,沒有仔細對照參數類型,或直接以爲JSONObject與Map之間就是互逆轉換,直接把排查問題的方向定位到JSON序列化的工具上,方向偏了,越走越遠
  2. 適可而止,不要急於求成

    1. 不要一條道跑到黑,三十分鐘沒有結論,就說明要不方向錯了,要不解決方案不正確,及時調整方向,避免過度糾結
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章