1、为什么需要Debug

目的:开发过程中 查找或定位错误或者阅读源码

程序运行的结果(4种情况)

情况1:没有任何bug,程序执行正确!

情况2: 运行以后,出现了错误或异常信息。但是通过 日志文件或控制台 ,显示了异常信息的位置。

情况3: 运行以后,得到了结果,但是结果不是我们想要的。 情况4: 运行以后,得到了结果,结果大概率是我们想要的。但是多次运行的话,可能会出现不是我们想要的情况。比如:多线程情况下,处理线程安全问题

2、Debug的步骤

1、添加断点 2、启动调试 3、单步执行 4、观察变量和执行流程,找到并解决问题

■ 断点的添加、取消、查看

  • 添加/取消某个位置的断点:点击行号位置

  • 查看所有断点:Ctrl + Shift + F8

  • 取消所有断点: 点击查看所有断点,不勾选Java Line Breakpoints

调试中的断点意义:执行到了即生效了,就会暂停一下。

打多个断点的意义:整个项目也可以打一个断点,然后执行到想要观察的方法的调用,通过step into 进入观察,但是可能点快了,直接完执行方法调用。但是项目工程比较大,对于想要观察的方法打上一个断点,执行到了,它就会生效暂停,暂停一下更方便而已。

■ 设置好断点后,启动选择debug方式启动:

  • debug 键的位置:行号点击三角形可以选择,代码内容空白位置右键可以选择,菜单工具栏的运行臭虫子图标可以选择

  • 代码中的打印、日志语句,执行后,在Debug模式下Console 观察

  • 变量区的变量注意是当前方法栈的

3、idea 调试快捷键

4、总结一下调试快捷键的使用

(1) 常用的:

观看下一步的单步调试[F8],进入方法体内部[F7],退出方法体,执行下一步[Shift+F8],直接跳到下一个断点[F9]

(2) 走神了:

回到当前文件断点位置[Alt+F10],跳到光标[Alt+F9],

太走神/观察不细致,那就重来一遍:回退到上一个方法调用的开始处[Drop Frame]

(3) 结束:

结束调试[Ctr+F2]、让当前断点后面的所有断点失效[Mute Breakpoints]

5、调试过程的其他小技巧

(1) Ctr+鼠标

  • 点击目标进入,再次点击,如果不能再进入则会出来。目标可以是属性对象,也可以是类、是接口,是方法等等。

(2) Alt+箭头方向←

  • 让光标回到上一个光标位置。有时候,因为Ctr+鼠标点击进入之后,在不移动光标位置,想退回上一个光标位置,那么Alt+←

(3) 全局搜索快捷键

  • Ctr+Shift+F

  • Ctr+Shift+N

(4) 定位当前打开的文件的位置

  • 定位当前文件所在项目目录结构位置:

6、断点细分(重点:条件断点、线程调试)

(1) 方法断点:

  • 刚进入方法会停顿一下

(2) 字段断点:

  • 默认会停顿在字段值发生改变的位置

(3) ☺ 条件断点----适合观察循环体的代码执行流程

  • 可以在断点位置,设置暂停的条件,右键断点

(4) 异常断点:

  • 设置某种异常暂停

(5)☺ 线程调试:

  • 设置,观察某个线程的执行

7、调试实践和心得总结

举例分布式项目调试,比如有三个应用:admin应用-将任务主体存储到redis,master应用-将redis任务主体进行执行。其中,master实际上是远程调用了worker应用-去执行任务主体。

(1) 多个应用调试观察执行流程:

  • 要注意流程中应用执行,从A应用执行着到了应用B应用,然后再继续执行到应用C,调试的时候,也要跟着流程切换应用的调式模式。

  • 当A应用debug着,突然卡着的时候,就需要考虑这时候执行流程是不是进入了应用B了,切换到应用B的debug模式观察一下。

  • 切换到C应用的时候,观察执行下一步,迟迟不肯进入下一步,考虑是不是A应用是不是得“放行”,B应用执行到下一步,C应用才有资格进行执行。

(2) 打断点要注意远程调用的代码位置不能打,否则项目跑不起来

举例:在@FeignClient的接口中的方法打了断点,导致项目启动失败。

  • 执行流程:A服务远程调用B服务
// A服务,将chatExecParam 发送给B服务[worker] 去执行
workerWebservice.execChat(chatExecParam);

// 中间的Fegin负载均衡
@FeignClient("chat-worker")
public interface WorkerWebservice {
    @RequestMapping(value = "/execChat", method = RequestMethod.POST)
    boolean execChat(@RequestBody CrawlerExecParam crawlerExecParam);  //《---在这里打了断点,导致A服务启动失败 
}

// B服务
@Override
@RequestMapping(value = "/execChat", method = RequestMethod.POST)
public boolean execCrawler(ChatExecParam chatExecParam) {
   workerContext.getThreadPool().execute(new ExecQueueScanRunnable(chatExecParam, masterWebservice));
   return true;
}
  • 错误信息:
2023-03-11 22:45:38.162 [WARN ] [main] com.netflix.config.sources.URLConfigurationSource - No URLs will be polled as dynamic configuration sources.
2023-03-11 22:45:38.172 [INFO ] [main] com.netflix.config.sources.URLConfigurationSource - To enable URLs as dynamic configuration sources, define System property archaius.configurationSource.additionalUrls or make config.properties available on classpath.
2023-03-11 22:45:38.855 [WARN ] [main] com.netflix.config.sources.URLConfigurationSource - No URLs will be polled as dynamic configuration sources.
2023-03-11 22:45:38.866 [INFO ] [main] com.netflix.config.sources.URLConfigurationSource - To enable URLs as dynamic configuration sources, define System property archaius.configurationSource.additionalUrls or make config.properties available on classpath.
2023-03-11 22:46:30.475 [INFO ] [main] o.s.scheduling.concurrent.ThreadPoolTaskExecutor - Initializing ExecutorService 'applicationTaskExecutor'
2023-03-11 22:47:43.098 [INFO ] [main] o.s.scheduling.concurrent.ThreadPoolTaskScheduler - Initializing ExecutorService 'taskScheduler'
2023-03-11 22:47:46.228 [INFO ] [main] com.alibaba.nacos.client.naming - initializer namespace from System Property :null
2023-03-11 22:47:46.275 [INFO ] [main] com.alibaba.nacos.client.naming - initializer namespace from System Environment :null
2023-03-11 22:47:46.315 [INFO ] [main] com.alibaba.nacos.client.naming - initializer namespace from System Property :null
  • 分析原因:[▷下次抽空补充!◀]~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

  • 解决:取消掉在@FeignClient接口下的方法打断点

(3) idea 卡着不动/debug 执行太慢:

  • 调试点击下一步,或者调试跳到下一个断点的时候,idea 卡着不动:

判断是否卡着:按键-结束调试是激活状态;重要的是在Variables 提示了一句:程序正在运行The application is running

程序真正(debug)结束

  • 原因分析

① 可能原因1:方法断点会使得正在debug调试的程序变慢【建议:少用方法断点

② 可能原因2:断点打太多建议尽量不要在项目里打过多的断点,调试哪里就在哪里打上,调试完把断点去掉就好。

③ 可能原因3:执行的方法是远程方法(和网络有关)或者执行的方式是数据库操作有关。

☺ 心得总结

1、 建议:少用方法断点

2、 建议:不要打太多断点,为了观察方便,需要再打,观察完,可以去掉断点。

3、注意:如果项目是分布式项目,负载均衡@Feign的接口中的方法【 本来就不建议在方法的位置打断点了! 】,如果影响了项目启动,请取消断点。

如果本文对你有帮助的话记得给一乐点个赞哦,感谢!

作者:|一乐乐|,原文链接: https://www.cnblogs.com/shan333/p/17208004.html

文章推荐

Blazor实战——Known框架增删改查导

优秀的流程图应该怎样绘制呢?

redis 事务与管道

SpringBoot 使用 Sa-Token 完成权限认证

Elasticsearch搜索功能的实现(五)-- 实战

最新版本 Stable Diffusion 开源 AI 绘画工具之汉化篇

在Winform分页控件中集成导出PDF文档的功能

一文了解清楚kafka消息丢失问题和解决方案

如何查看一个 pytorch 的 tensor 占用了多少字节

传输安全HTTPS

配置 Spring Security 登录后重定向到不同的页面

Mybatisi和Spring整合源码分析