远程debug真的很有用,我个人的真实经历就是有一次,我新开发的功能,在生产上没生效,我询问了运维多次,运维也多次确认回复说是最新的包,又是查日志,对数据,仍然没发现问题,最后我就采用远程debug发现我新开发的代码不存在。
所以不需要不要紧,但是要会,作为应急处理办法。
来源:本文基于学会 IDEA 远程 Debug 调试,直接线上秀操作一文进行转载、修订、补充
高低版本的 IDEA 的设置可能界面有点不一样,我用2020.1.1的。大致上差不多,自行摸索。
注意:注意端口别被占用。后续这个端口是用来跟远程的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变得安全了,远程调试只允许本地,如果要远程,则需要在端口前配置*
使用idea配置得到的 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 和 &
如果远程调试在自己的断点处停下来了,此时关闭IDEA中的项目停止运行,则还会继续运行执行完剩下的逻辑吗?会的,这点比较不容易记住
以下面的代码为例,在第一行停住了。然后IDEA中停掉,发现停掉之后控制台还是打印了剩下的日志。
IDEA 里的代码如果不和jar包的一致,会怎么样。
结论:要保证和远程启动的代码一致。
否则你debug的时候的行数会对不上。报错抛异常倒是不会。像这种还是能对得上行数的
比如你调试test1方法,test2方法在test1下面,在test2里加代码,这样并不影响test1中的行号,这种是可以在调试的时候准确反应行号的。(我也就是在细节上发现的生产代码与我本地代码不一致的)
日志不会打印在IDEA的控制台上。即System.out 以及 log.info 还是打印在远程的。
远程调试的时候,打了断点,停住后会不会导致页面的请求卡住。
比如你使用远程调试,别的QA在测试这个页面,结果他们看到的结果是怎么样的?会卡住吗?会的,已经实际遇到过这种情况了。
如果在远程调试过程自己发现了bug,本地改好后重新启动IDEA里的项目,再到页面调用一次,能修复吗?不能,运行的还是远程部署的jar中的代码
关于drop frame的问题,如果Drop Frame了重新进行调试,会不会插入2条记录?
这里先说一下Drop Frame是什么,在idea的调试器中查看应用程序的调用堆栈,使用Drop Frame功能,可以回退到前一个堆栈帧,从某种意义上说可以回到过去.如果您错过了想要再次查看的关键点,这有助于重新输入函数。简单来讲就是返回到上一个调用方法。
可能有小伙伴会问:怎么我Debug的时候找不到Drop Frame呢?
其实这个是跟版本有关,在2022.1版本之前叫Drop Frame,之后改为了Reset Frame。
好,继续我们的问题,如下图 userMapper.insert(eo) ,本方法没有使用 @Transactional 修饰,mapper方法执行过后事务会被立即提交,则库表里多了一行记录,如果Drop Frame后,再次进行调试,再次执行这代码,于是又插入了一条记录。
如果加上 @Transational 就不会有两条记录了,Drop Frame的时候事务没被提交,再次执行该插入代码也不会插入2条。
如果把上述插入数据库的逻辑,换成调用远程的接口,在Drop Frame后,再次执行相同的代码,会不会导致远程接口被执行了2次?会的。