IDEA debug 小技巧,任意时刻执行任意实例的任意代码

531 阅读2分钟

今天调试的时候,发现了一个令我震惊的功能,不知道是不是我孤陋寡闻了,但是这个功能我觉得实在是太变态了

众所周知,在Idea进入断点的时候,可以加载内存中类实例

image.png

image.png

这里可以搜索到我们想要找的实例对象 比如有一个controller

@RestController
public class TestController {
    @GetMapping("/testC")
    public String test(){
        long l = System.currentTimeMillis();
        System.out.println(l);
        return String.valueOf(l);
    }
}

image.png

右键 Show Instances

image.png

然后再右键你想选择的实例 评估表达式

image.png

这个时候我们就可以看到,评估窗口自动填充了一个对象(没有展开点击右上角展开按钮)

image.png

如果我们输入一个 . ,神奇的事情发生了,我们可以直接用这个实例!What Fxxx! 竟然可以从内存中取任意一个实例并且随手拿来用??

image.png

image.png

甚至可以在这里面调用静态方法,写局部变量,点击评估就可以显示最后一个变量的结果,就相当随时更改 随时编译并且保持上下文变量不变的一个方法体???如果断点在一个方法,还使用方法的局部变量,这个功能太变态了,我甚至以为自己在浏览器里写JS而不是java

image.png

然而,还有更变态的用法:
当在一个实例上点击“评估表达式”时,固然会带出这个实例的变量,但是如果想要同时获取多个实例,目前的方法就不行了,点击两个实例评估,就会出现两个评估窗口,但是两个评估窗口之间的实例并不共享

image.png

聪明的同学想必已经知道怎么办了,我们可以使用一个静态Map将这个实例引用存下来然后再另一处地方取出来!

public class TestController {

    static Map<String,Object> objectMap = new HashMap<>();

    public static void putObject(String key, Object value) {
        objectMap.put(key,value);
    }

    public static Object get(String key) {
        return objectMap.get(key);
    }
}

点击评估,将对象存入map
image.png

然后在另外一个窗口取用:

image.png

这样就可以随时拿到任何变量了,真心感觉这个功能很强大,不知道为什么Idea没有继续开发,如果把这个开发成一个随时拿任何实例,随时跑任何方法,不用重启Spring 也不用反复修改编译的专门的功能,估计就要乐死了

不过目前的功能已经很强大了,特别是调试不了解的API,只要改一改点一下评估就能在同一个上下文反复一键运行,实在是太方便了,开发效率真的直线提升

另外附赠一个小技巧,如果想要随时进断点,用评估测试代码,但是每次都要用postman什么的发起,可以试试这个:

@Configuration(proxyBeanMethods = false) 
//记得把这个类放入git的.gitignore 不然上传到生产库可就炸了 
//小项目也可以用`@Profile("dev")`只让它在指定环境生效
public class DebugConfig {
    @PostConstruct
    void thread() {
        Thread thread1 = getThread1();
        thread1.start();
        Thread thread2 = getThread2(new ThreadProxy(thread1));
        thread2.start();
    }

    Thread getThread1() {
        return new Thread(() -> {
            try {
                Thread.sleep(Integer.MAX_VALUE);
            } catch (InterruptedException ignored) {
            }
        }, "01断点线程");
    }

    Thread getThread2(ThreadProxy thread1) {
        return new Thread(() -> {
            while (true) {
                if (!thread1.getThread().isAlive()) {
                    System.out.println("砸瓦鲁多"); //断点打在这里
                    thread1.setThread(getThread1());
                    thread1.getThread().start();
                }
            }
        }, "02观察线程");
    }

    @Data
    @AllArgsConstructor
    static class ThreadProxy {
        private Thread thread;
    }
}

然后在线程窗口,中断断点线程就会自动进入砸瓦鲁多断点,随时随地进入断点,配合评估非常方便

image.png