排查Java反射調用的InvocationTargetExcetion問題

在Java中通過反射調用方法時,常見的一個異常是:java.lang.reflect.InvocationTargetException,將異常信息打印到日誌文件中時通常會有如下一句信息:java.lang.reflect.InvocationTargetException: null,由於在異常信息中存在"null",一開始就會非常敏感,會誤以爲是空指針異常。
其實不然,從java.lang.reflect.Method.invoke()方法註釋描述中可以知道,當拋出InvocationTargetException異常時表明是在執行底層方法時異常。這裏的“底層”並不是指JDK的底層實現,而是相對於反射調用的入口而言,通常是業務代碼的實現方法。
Java反射調用Method_invoke

實際上,當出現InvocationTargetException異常時通常會在異常堆棧中同時存在一個提示:Caused by: xxx,只要根據這個提示就能很快定位到具體問題。

最後再來解釋日誌信息中爲什麼會出現一個關鍵字“null”,這很容易讓人誤以爲是業務代碼出現了空指針異常!
這是因爲在通過日誌框架打印異常信息時,會將Throwable.detailMessage屬性打印出來,由於在反射調用時InvocationTargetException異常是Java本地方法拋出的,此時該異常對象的detailMessage屬性爲null,因此在打印出來的日誌信息中就看到了“null”關鍵字,這並不表示是業務代碼中拋出了空指針異常。

如下示例代碼:

public class ReflectionTest {
    private static final Logger LOGGER = LoggerFactory.getLogger(ReflectionTest.class);
    public static void main(String[] args) {
        try {
            ReflectionTest test = new ReflectionTest();
            Method method = test.getClass().getMethod("methodInvokeTest");
            method.invoke(test);
        } catch (Exception e) {
            LOGGER.error("{}", "test", e);
        }
    }

    public void methodInvokeTest() {
        if (1 == 1) {
            throw new RuntimeException("在業務方法中拋出異常");
        }
    }
}

在DEBUG時可以看到InvocationTargetException對象的detailMessage屬性爲空。
InvocationTargetException_detailedMessage_null

在打印的日誌信息中同樣存在InvocationTargetException: null(其實在業務代碼中拋出的並非空指針異常)。

2024-05-06 17:46:22,228 ERROR [main] o.e.j.ReflectionTest [ReflectionTest.java:20] test
java.lang.reflect.InvocationTargetException: null
	at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) ~[na:1.8.0_261]
	at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) ~[na:1.8.0_261]
	at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) ~[na:1.8.0_261]
	at java.lang.reflect.Method.invoke(Method.java:498) ~[na:1.8.0_261]
	at org.example.java.ReflectionTest.main(ReflectionTest.java:18) ~[classes/:na]
Caused by: java.lang.RuntimeException: 在業務方法中拋出異常
	at org.example.java.ReflectionTest.methodInvokeTest(ReflectionTest.java:26) ~[classes/:na]
	... 5 common frames omitted

分析完畢!

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章