有时我们需要进行远程debug,本文研究如何进行远程debug和使用 IDEA 远程debug过程中的细节。看完可以解决一些疑惑。
配置以springbot微服务为例,远程debug服务。
首先,需要添加特定的参数来启动springboot。
IDEA设置高低版本的 IDEA 界面可能有点不一样,我用2020.1.1.大致相同,自己摸索。
IDEA打开springbot应用程序对应的远程启动
- 选择 Edit Configuration
- 如图所示,点击加号,选择Remotee
- 详细步骤见图
注:注意不要占用端口。后续端口用于与远程java进程通信。
可以注意到,切换不同的jdk版本,生成不同的脚本
选择 jdk1.4,则为
-Xdebug -Xrunjdwp:transport=dt_socket,server=y,suspend=n,address=50055
这就是为什么你搜索其他博客会有这样的配置。事实上,这种配置也是可行的。但更准确的配置应遵循以下jdk5-8
选择 jdk 5-8,则为
-agentlib:jdwp=transport=dt_socket,server=y,suspend=n,address=50055
选择 jdk9以上,则为
-agentlib:jdwp=transport=dt_socket,server=y,suspend=n,address=*:50055
据说由于jdk9变得安全,远程调试只允许本地调试。如果需要远程调试,则需要在端口前配置*
用第一步得到的Command line arguments for remote JVM
即可,即-agentlib:jdwp=transport=dt_socket,server=y,suspend=n,address=50055
改造后的启动脚本如下
nohup java \-agentlib:jdwp=transport=dt_socket,server=y,suspend=n,address=50055 \-jar remote-debug-0.0.1-SNAPSHOT.jar &
注意在windows中使用 ^ 以换行为例
java ^-agentlib:jdwp=transport=dt_socket,server=y,suspend=n,address=50055 ^-jar remote-debug-0.0.1-SNAPSHOT.jar
说明:
- 端口可以自己设置,没有被占用,但应该与IDEA中的remote中设置的端口一致!复制其他参数。详细的参数解释可以参考附录或自己搜索
remote-debug-0.0.1-SNAPSHOT.jar
改成给自己的 jar 包名字- 我给的脚本是后台操作的。如果不需要后台操作,可以自己去掉。
nohup
和&
- 启动springboot,启动IDEA
如果在自己的断点停止远程调试,此时关闭IDEA中的项目并停止运行,剩余的逻辑会继续运行吗?是的,这不容易记住
以下代码为例,在第一行停止。然后IDEA停止,发现控制台在停止后打印了剩余的日志。
细节2:jar包代码与本地不一致会怎么样?IDEA 如果里面的代码和jar包不一致,会怎么样?
结论:确保与远程启动代码一致。
否则,当你debug时,行数将不匹配。报错抛异常是不会的。像这样的行数仍然可以匹配
例如,您调试test1方法,test2方法在test1下,在test2中添加代码,这不会影响test1中的行号,这可以在调试过程中准确反映行号
细节3:日志打印在哪里?IDEA控制台上不会打印日志。也就是说System.out
以及log.info
或者打印在远程。
@GetMapping(/test1)public String test1() { System.out.println(第一行); System.out.println(第二行); log.info("log 第一行"); log.info("log 第二行"); return "ok";}
细节4:其他人会在调试过程中卡住吗?远程调试时,打断断点,停止后是否会导致页面请求卡住。
例如,如果您使用远程调试,其他QA正在测试此页面。他们看到的结果是什么?它会卡住吗?是的,我实际上遇到过这种情况。
细节5:当本地代码修复bug远程调用时如果在远程调试过程中发现bug,在当地修改后重新启动IDEA中的项目,然后在页面上调用,可以修复吗?不,远程部署的jar中的代码运行
这直接打破了远程页面点触发本地代码进行debug的梦想。如果可以的话,调试代码就太方便了。
细节6:这不是远程调试的问题,而是dropframe的问题。我们在这里谈谈关于drop frame
如果是的问题drop frame
重新调试后,会插入两个记录吗?
如图userMapper.insert(eo)
,该方法未使用@Transactional
修改后,如果实施mapper方法后事务会立即提交,库表中会有一行记录。drop frame
之后,再次调试,再次执行代码,然后插入另一个记录。
如果加上@Transational
不会有两个记录。dropframe时事务未提交,插入代码再次执行时不会插入两个。
drop是什么? frame
细节7:和上面一样,dropframe也是一个问题如果用调用远程接口代替上述插入数据库的逻辑,dropframe后再次执行相同的代码,会导致远程接口执行两次吗?是的。
总结远程调试似乎没有那么有用,不能用作长期调试工具。只能作为临时调试的手段。
有几个困难:
- 很难确定本地代码是否与远程代码一致,也很难判断它们是否一致
- bug是通过远程调试发现的,但不能在立即修复后继续调试,只能在修复后进行远程调试