背景知识
Java提供了一个很方便方便调试工具,其使用名为JDWP(Java Debug Wire Protocol)协议用于连接调试器和目标程序的协议。JVM自带该协议,我们可以通过命令查看java -agentlib:jdwp=help 帮助信息。
我们一般是在启动调试程序的Java命令行参数中使用JDWP,使用方式如下java -agentlib:jdwp=transport=dt_socket,server=y,suspend=n,address=5005 OurApplication,在启动java应用程序是,增加-agentlib:jdwp=transport=dt_socket,server=y,suspend=n,address=5005参数则表示以调试模式启动应用程序
这里需要先说明两个概念,调试器和被调试程序:
调试器(debugger):指我们在客户端调试用的程序,如我们在idea上新建一个Remote JVM Debug,此时idea为我们新建了一个调试器
被调试程序(debugee):顾名思义,就是我们运行的程序。
其中各个参数的说明如下:
transport,可选值有
dt_socket. 表示通过socket连接,是一个通用的传输方式,可以跨机器连接,也就是调试器和被调程序可以不在一台机器上,当然也可以在同一台机器上。所以这种一般是我们比较常用的模式
dt_shmem,表示使用共享内存,此种方式限制了被调试程序和调试器在同一台机器上。
server,如果为y的话,表示等待调试器连接,如果为n的话,表示连接address指定的调试器,这两者的区别
当值为y的时候,可以理解成被调试程序先启动,然后等待调试器连接,一般远程调试的时候设置的值就是y
当值为n的时候,是调试器先启动,然后程序在启动时连接到程序器,我们在本地idea调试的时候,设置的值就是n
suspend,是否阻塞,如果为y的话,目标程序的VM启动会暂停,直到有调试器连接的时候才会继续,如果为n的话,目标程序VM会正常启动
address,传输连接的地址,如果server为n的话,表示debugger的地址,如果server=y 的话,表示服务器监听地址
实战
前置准备
我们准备如下代码
package com.demo.main;
/**
* @author
*/
public class Main {
public static void main(String[] args) {
System.out.println("hello world");
}
}
同时因为为了打出一个可执行的jar包,这里在pom文件中引入了maven-assembly-plugin, 内容如下
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-assembly-plugin</artifactId>
<executions>
<execution>
<phase>package</phase>
<goals>
<goal>single</goal>
</goals>
<configuration>
<archive>
<manifest>
<mainClass>
com.demo.main.Main
</mainClass>
</manifest>
</archive>
<descriptorRefs>
<descriptorRef>jar-with-dependencies</descriptorRef>
</descriptorRefs>
</configuration>
</execution>
</executions>
</plugin>
</plugins>
</build>
执行命令 mvn clean install 打出一个可执行的jar包
以debug方式启动被调试程序
在打出可执行jar包之后,执行如下命令
java -jar -agentlib:jdwp=transport=dt_socket,server=y,suspend=y,address=5005 remote-debug-demo-1.0-SNAPSHOT-jar-with-dependencies.jar
此时程序并不会直接执行,会打印一行内容
Listening for transport dt_socket at address: 5005
看到如下日志,表示启动成功。
程序不会执行的原因是我们设置了suspend=y,表示阻塞等待调试器连接。如果我们是一个web服务器程序,可以设置为n,这样不会阻塞vm的启动,
Idea中启动调试器
我们现在对应代码上打好断点
然后新建一个Remote JVM Debug,这里我录制了一个gif
相关参数的我通过截图说明:
然后就是启动调试了:
参考资料
https://docs.oracle.com/javase/8/docs/technotes/guides/jpda/conninv.html#SPI
https://www.baeldung.com/java-application-remote-debugging