Java 调试原理
Java平台调试体系结构(Java Platform Debugger Architecture,JPDA)
参考
# JPDA体系概述
- Java程序是运行在
JVM
上的 - 调试java程序,事实上就是 向虚拟机请求其当前的运行状态 等
JPDA
就是虚拟机提供的 一整套用于 java 调试的 工具 和 接口。
JPDA可以分为三个部分
-
Java虚拟机 工具接口(JVMTI,JVM Tool Interface)
-
Java调试线 协议(JDWP,Java Debug Wire Protocol )
-
Java 调试接口(JDI,Java Debug Interface)。
远程调试案例
1. 创建一个java项目,并写一个简单类
项目名 remote-debug-java
import java.util.Date;
public class DeadCycled {
public static void main(String[] args) {
boolean cycle = true ;
boolean print = true ;
while (cycle) {
if(print) {
System.out.println(new Date());
}
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
2. 打包成可执行 jar 包
普通 java 项目,可以直接点 debug 就可执行了
(这是因为,开发工具帮你配置好了。)
而我们现在要手动配置
- 生成可执行 jar 包
执行 jar 包 ,同时启动 debug 服务
参考:java实现远程调试
执行 jar 包命令
java -jar remote-debug-java.jar
而我们现在要启动 debug 服务器 (开启debug接口)
所以,先关了 ctrl + c
重新输入命令
java -agentlib:jdwp=transport=dt_socket,server=y,suspend=n,address=5006 -jar remote-debug-java.jar
新命令运行后,控制台会显示,开启了 5006 端口
这就是 debug 服务端的端口。
后面只需要用客户端连接上端口,即可实现远程调试
必要说明
-
jdk1.7版本之前,命令为:
java -agentlib:jdwp=transport=dt_socket,address=8000,server=y,suspend=y -jar xxx.jar
1.7版本之后
可仍然使用之前的命令:java -agentlib:jdwp=transport=dt_socket,address=8000,server=y,suspend=y -jar xxx.jar
或新命令
java -Xdebug -Xrunjdwp:transport=dt_socket,server=y,suspend=n,address=8000 -jar test.jar
-
命令参数详解(新命令为例)
java -Xdebug -Xrunjdwp:transport=dt_socket,server=y,suspend=n,address=8000 -jar test.jar
- -Xdebug:通知JVM工作在debug模式下;
- -Xrunjdwp:通知JVM使用(java debug wire protocol)来运行调试环境;
- transport:监听Socket端口连接方式
(也可以dt_shmem共享内存方式,但限于windows机器,并且服务提供端和调试端只能位于同一台机); - server:server=y表示当前是调试服务端,=n表示当前是调试客户端;
如果你想将当前应用作为被调试应用,设置该值为 y;
如果你想将当前应用作为客户端,作为调试的发起者,设置该值为 n。 - suspend:suspend=n表示启动时不中断,一般用于设置主动连接;suspend=y表示启 动时就进入调试模式,一般用于被动连接;
主动连接调试:
服务端配置监控端口,本地IDE连接远程监听端口进行调试,一般调试问题用这种方式。
被动连接调试:
本地IDE监听某端口,等待远程连接本地端口。一般用于远程服务启动不了,启动时连接到本地调试分析。
-
现在启动的是端口的提供者,我们称为 debug 服务端
(接下来,启动 debug 客户端)
注意:这个服务端、客户端是相对的。
如果是 idea开发工具在监听,那么idea是服务端。
而现在,是 启动的程序在监听,所以启动的程序是服务端,idea 是客户端。
因此,响应的,程序的 server=y, 而(下面启动的)idea 的 server=n
debug 客户端 启动
以 idea 为例
(eclipse 类似,甚至更简单,可参考:https://www.cnblogs.com/wwywwy/p/9626078.html)
用 idea 打开 jar 包的源码(不是源码,调试会异常哦~)
(下图)生成的命令预览,是 debug 服务的命令预览!
(即 jar 包 添加这个命令,可以开启服务器)
点击后,可以看到,程序暂停了,并且 idea 进入了 debug 界面。
说明 debug 客户端远程连接成功!
debug 客户端 断开
其他形式的 debug 服务端
-
普通java程序配置
示例:java -agentlib:jdwp=transport=dt_socket,server=y,suspend=n,address=5006 -jar chess-server.jar
-
tomcat中web项目配置
在tomcat的bin
目录中,新建setenv.sh
文件,输入:
CATALINA_OPTS="-agentlib:jdwp=transport=dt_socket,server=y,suspend=n,address=5006"
-
如果是windows系统,新建
setenv.bat
文件,输入:
SET CATALINA_OPTS=-agentlib:jdwp=transport=dt_socket,server=y,suspend=n,address=5006
tomcat启动后会自动调用setenv文件,进行jvm参数设置
简单的 java 程序 远程调试
done~
maven 启动 springboot 的 debug 模式
参考:
有的项目需要命令行启动,每次到 target 目录下输入命令行很麻烦。
maven 提供了 操作 springboot 的命令行(其实是操作 java)
仔细看 springboot 的 pom.xml 文件 插件 部分。
都会有 spring-boot-maven-plugin
这个插件
可以用 maven 命令 操作 springboot
比如
我们先在 idea 开启一个 debug 的监听模式服务器
开启 debug 客户端的方法有两种。
-
可以在 项目根目录 输入下面命令,启动 springboot 的调试模式。
mvn spring-boot:run -Dspring-boot.run.jvmArguments="-Xdebug -Xrunjdwp:transport=dt_socket,server=n,suspend=y,address=5005"
注意,这时候是客户端,server=n
-
或者在 pom 文件中就写好了 jvm 参数
<project> ... <build> ... <plugins> ... <plugin> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-maven-plugin</artifactId> <version>2.2.5.RELEASE</version> <configuration> <jvmArguments> -Xdebug -Xrunjdwp:transport=dt_socket,server=y,suspend=y,address=5005 </jvmArguments> </configuration> ... </plugin> ... </plugins> ... </build> ... </project>
两种客户端,只要一开启,就会被 服务端监听到,从而进入 debug 模式。
当然,你也可以让程序作为服务端,idea 作为客户端,道理一样,就换一下 server,和启动的顺序
debug启动 CAS 服务
有了前面的 铺垫,启动 cas 服务的debug 模式是水到渠成的。
这个项目作为例子:github 服务端 : https://github.com/LawssssCat/v-cas
更爽的是,cas 官方还提供了更简便的方法启动 debug 模式
只需要在 项目根目录执行下面指令:
#我这个是window系统,所以使用的是cmd
build.cmd debug
# linux 系统是 build.sh debug
测试的监听端口号为5000
注意:这时候是 应用为服务端
因此,下面我们开启 idea 作为 debug 的客户端连接上程序
添加debug调试 客户端
弄好配置后,开启debug ,就能看到连上了 的提示。
如果在相应的处理器上加断点。会开始调试
原理
打开build.cmd文件,大家可以看到下面这句话
:debug
call:package %1 %2 %3 & java %JAVA_ARGS% -Xdebug -Xrunjdwp:transport=dt_socket,address=5000,server=y,suspend=n -jar target/cas.war
@goto:eof
命令解释
可以看成两个命令:
mvn clean package
(解释:maven 把项目清理,然后打包)java -Xms500m -Xmx1g -Xdebug -Xrunjdwp:transport=dt_socket,address=5000,server=y,suspend=n -jar target/cas.war
(解释:运行 target 目录下 cas.war 文件,同时设定一些参数,包括 开启 debug 服务端)
其他一些命令的解释
:
批处理标签引导符%
批处理变量引导符CALL
从另一个批处理程序调用这一个。