Advertisement

使用 IDEA 远程 Debug 调试

阅读量:

背景

在某些情况下,进行远程调试是一项必要的技能,在本研究中我们探讨了如何实现远程调试这一技术要点,并详细分析了使用IDEA软件执行远程调试时所涉及的关键步骤。通过阅读本文内容,读者将能够解答一些关于远程调试的问题。

配置

远程调试服务是一种常见的技术手段,在Spring Boot微服务架构中尤其常见。通常情况下,在配置环境中添加以下必要的组件即可实现功能:启动一个基于Spring Boot的微服务框架通常需要附加特定的启动参数

启动脚本改造

搭建一个基于Spring Boot的Web测试应用,并将其打包为JAR文件;随后部署至远程服务器;最后优化原有的启动配置文件。

使用第一步得到的 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 demo.jar &

注意在windows中用 ^ 来进行换行,例如:

复制代码
 java ^

    
 -agentlib:jdwp=transport=dt_socket,server=y,suspend=n,address=50055 ^
    
 -jar demo.jar

说明:

可以选择任意可用端口,并非必须与IDEA远程设置的一致。需要注意的是,在启动远程连接时必须与IDEA远程配置中的设置保持一致。对于详细的操作说明,请参考附录内容或自行查阅相关资料。

2、demo.jar 改成给你自己的 jar 包名字

3、脚本是后台运行的,如不需要后台运行,自行去掉 nohup 和 &

3、启动远程服务器中的springboot项目

IDEA配置

不同版本的 IDEA 配置可能存在界面差异。
我采用的是 2021 年 2 月 1 日的那个版本。
大体类似,并且自己尝试过一些配置方案。

IDEA打开远程启动的springboot应用程序所对应的

1.选择 Edit Configuration

2.如图,点击加号,选择Remote

3.配置,详细步骤见图

注意:注意端口别被占用。后续这个端口是用来跟远程的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

建议采用JDK 9及以上版本。据说是因为JDK 9版本更加安全了,在进行远程调试时仅限本地环境。如果需要进行远程调试,则需在端口前配置相关参数。

复制代码
    -agentlib:jdwp=transport=dt_socket,server=y,suspend=n,address=*:50055

IDEA远程调解的细节

细节1:停在本地断点,关闭程序后会继续执行吗

当远程调试在断点处停止时,在关闭IDEA中的项目停止运行后,在这种情况下是否会继续执行剩余的逻辑?是的,在这种情况下会继续执行剩余的逻辑,并且这一点需要特别注意和记忆。

以如下代码为例,在第一行处陷入停滞。当我们在IDEA中触发停止时,发现即使在程序停止后,控制台仍会输出剩余的日志信息。

细节2:jar包代码和本地不一致会怎么样?

IDEA 里的代码如果不和jar包的一致,会怎么样。

结论:要保证和远程启动的代码一致。

在调试过程中,如果你无法对齐行数,则可能出现问题.但是错误处理通常会正常.类似情况仍然能够保持行数对齐.

当你调试时,在嵌套的方法中添加代码块不会干扰到父方法所在的行号范围;这种方法能够在调试过程中精确反映各行的编号。

细节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的问题,放在这里一起讲了

关于frame drop的问题,在frame drop之后再次调试时是否会插入两条记录?

如图所示,在用户Mapper中调用insert(eo)操作。需要注意的是,默认情况下本方法未配置事务控制关键字 @Transactional。当mapper方法完成之后会立即提交事务,则会导致库表中新增一条记录。如果在drop frame之后重新调试并重新运行该代码时,则会再插入一条记录。

当启用 @Transational 事务隔离级别时,断开时事务未提交;再次运行此插入语句也不会产生两条记录。

关于什么是drop frame

细节7:跟上面一样,是dropframe问题

如果我们采用调用远程接口替代数据库插入逻辑,在dropframe之后重新运行相同的操作流程,并且这样做会不会导致远程接口被执行两次?答案是会。

总结

从感觉上来看,并不觉得远程调试的应用范围非常广泛;它无法作为一种长期使用的调试工具;相反地,在这种情况下它只能作为一个辅助手段使用

难点有几个:

1.难保证本地代码和远程一致,而且你也很难判断是否一致。

利用远程调试手段识别出了问题;然而却无法在修复后再继续进行后续调试;因此必须是在完成修复操作之后才能进行部署并持续执行远程调试

全部评论 (0)

还没有任何评论哟~