背景知识

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包

java调试器命令 java 调试器_调试器

以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中启动调试器

我们现在对应代码上打好断点

java调试器命令 java 调试器_java调试器命令_02


然后新建一个Remote JVM Debug,这里我录制了一个gif


相关参数的我通过截图说明:

java调试器命令 java 调试器_调试程序_03


然后就是启动调试了:

java调试器命令 java 调试器_java调试器命令_04

参考资料
https://docs.oracle.com/javase/8/docs/technotes/guides/jpda/conninv.html#SPI https://www.baeldung.com/java-application-remote-debugging