[ Coding七十二绝技 ] 如何利用Java异常快速分析源码

异常一个神奇的东西,让广大程序员对它人又爱又恨。
爱它,通过它能快速定位错误,经过层层磨难能学到很多逼坑大法。
恨他,快下班的时刻,周末的早晨,它踏着七彩云毫无征兆的来了。

[ Coding七十二绝技 ] 如何利用Java异常快速分析源码

今天,要聊的是它的一项神技 : 辅助源码分析
对的,没有听错,它有此功效,只不过我们被恨冲昏了头脑,没看到它的美。

[ Coding七十二绝技 ] 如何利用Java异常快速分析源码

前情铺垫

讲之前,先简要铺垫下需要用到的相关知识。

1

了解点jvm知识都应该知道每个线程有自己的JVM Stack,程序运行时,会将方法一个一个压入栈,即栈帧,执行完再弹出栈。如下图。不知道也没关系,现在你也知道了,这是第一点。

[ Coding七十二绝技 ] 如何利用Java异常快速分析源码


Java中获取线程的方法调用栈,可通过如下方式

 

public class Sample {

    public static void main(String[] args) {
        hello();
    }

    public static void  hello(){
       StackTraceElement[] traceElements = Thread.currentThread().getStackTrace();
       for(StackTraceElement traceElement : traceElements){
           System.err.println(traceElement.getMethodName());
       }
    }
}

输出结果如下:

getStackTrace
hello
main

可以看到,通上面图中的入栈过程是一致的,唯一区别是多了个getStackTrace的方法,因为我们在hello方法内部调用了。也会入栈。

2

上面说了,是每个线程有自己的方法栈,所以如果在一个线程调用了另一个线程,那么两个线程有各自的方法栈。不废话,上代码。

public class Sample {

    public static void main(String[] args) {
        hello();

        System.err.println("--------------------");

        new Thread(){
            @Override
            public void run() {
                hello();
            }
        }.start();
    }

    public static void  hello(){
       StackTraceElement[] traceElements = Thread.currentThread().getStackTrace();
       for(StackTraceElement traceElement : traceElements){
           System.err.println("Thread:" + Thread.currentThread().getName() + " " + traceElement.getMethodName());
       }
    }
}

输出结果如下:

Thread:main getStackTrace
Thread:main hello
Thread:main main
--------------------
Thread:Thread-0 getStackTrace
Thread:Thread-0 hello
Thread:Thread-0 run

可以看到,分别在主线程和新开的线程中调用了hello方法,输出的调用栈是各自独立的。

3

如果程序出现异常,会从出现异常的方法沿着调用栈逐步往回找,直到找到捕获当前异常类型的代码块,然后输出异常信息。代码如下。

public class Sample {

    public static void main(String[] args) {
        hello();
    }

    public static void  hello(){
       int[] array = new int[0];
       array[1] = 1;
    }
}

方法执行后的异常如下

Exception in thread "main" java.lang.ArrayIndexOutOfBoundsException: 1
    at com.yuboon.fragment.exception.Sample.hello(Sample.java:15)
    at com.yuboon.fragment.exception.Sample.main(Sample.java:10)

对比上面第一点的执行结果,是不是有些相似。

好了,基础知识先铺垫到这。

基于上面的铺垫,下来我们先快速试一把,看看效果。

小试牛刀

场景是这样的,不知到大家是否了解springboot启动时是如何加载嵌入的tomcat的,可能很多人专门看过,但估计这会也忘得差不多了。

下面我们利用异常来快速找到它的启动加载逻辑。

what ? 异常在哪呢,我正常启动也没异常啊。

是滴,正常启动是没有,那我能不能让它不正常启动呢?

一个正常的情况下,异常都是被动出现的,也就是非编码人员的主观意愿出来的。

内容版权声明:除非注明,否则皆为本站原创文章。

转载注明出处:https://www.heiqu.com/wpypwy.html