排查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

分析完毕!

posted @ 2024-05-06 20:59  nuccch  阅读(2210)  评论(0编辑  收藏  举报