需求场景
可以接触Java程序的运行环境,可以得到jar包,但是不能得到源码,并且程序很复杂,依赖多,配置杂,不好构建本地调试环境。在这样的场景下,如何进行远程调试?
环境介绍
要调试的程序demo.jar
这是一个普通的java程序,功能是打印"Hello, World!",然后循环计数。
正常启动命令:
1 | java -jar demo.jar |

IDEA环境

无源码情况下IDEA远程调试JAR包方法
1.加jdwp参数使demo.jar程序支持远程调试
1 | java -agentlib:jdwp=transport=dt_socket,server=y,suspend=n,address=0.0.0.0:5005 -jar demo.jar |

参数说明:
| 参数 | 解释 |
|---|---|
| -agentlib:jdwp | 使用Java Debug Wire Protocol(JDWP)来允许远程调试 |
| transport=dt_socket | 指定传输协议为socket |
| server=y | 设置为服务器模式。将等待一个调试客户端(如IntelliJ IDEA或Eclipse)连接到它。 |
| suspend=n | 如果设置为y,则JVM在启动时会挂起(暂停),直到调试客户端连接。这里设置为n,意味着JVM将立即开始执行,而不会等待调试客户端连接。 |
| address=0.0.0.0:5005 | 指定监听的IP地址和端口 |
2.随便建个Java工程,在依赖库里加入demo.jar
使用IDEA新建一个Java控制台窗口程序
1 | NewProject->Java->Create project from template->... |





在依赖库中加入demo.jar
1 | File->Project Structure->Libraries->点击+号->Java->选择demo.jar->... |




执行完上述操作之后,demo.jar被加到依赖库中。

3.添加远程调试配置(Remote JVM Debug)
1 | Edit Configurations->点击+号->选择Remote JVM Debug->配置远程IP与调试端口->... |



4.下断点开始调试
1 | 在依赖库中点开demo.jar->选中想要调试的class文件->在想要调试的地方下断点->选择远程调试配置->开始调试 |

触发了断点

为了展示动态调试能力,这里把i设置为111111并继续运行(在i上右键选择Set Value或者快捷键F2可修改变量的值)。


发现i已经被动态改变

--------------------------------
问题1.如果class文件去掉了调试符号,则断不下来,只能对函数名称处下断点,或者系统函数的代码下断点,这很不方便
(2024.11.11补充,IDEA 2024.2.4)
在没有符号的情况下,对业务代码函数体内的地方下断点失效。

对系统函数的代码下断点是可以的,但系统函数断点往往断的很频繁,离关键位置有点远,不方便。

在没有符号的情况下,对业务代码的add函数名称处下断点可以断下来,而对业务代码函数体内的地方下断点则断不下来。

相关信息
1.javac编译时添加-g:none可以去掉调试符号,或者使用加壳混淆工具基本也可以去掉调试符号。
1 | javac -g:none -d . D:\workspace_idea\demo\src\demo.java |
如果只是测试,可以把编译好的demo.class替换掉demo.jar里的对应class,会发现去掉调试符号后大小会变小。
2.没有符号的情况下,不清楚如何直接断在业务代码。有个比较繁琐的方法,感觉可行,但未实践。把想要分析的class拉出来反编译成java代码(无符号的demo.class->demo.java),然后把原jar包的资源当作依赖库,把java代码再重新编译成带符号的class(demo.java->有符号的demo.class),最后把带符号的class扔到jar包里。
