1 背景
最近在从Go程序员切换成Java程序员,在前期需要解决的一个重要问题就是在VS Code编辑器中如何进行Java代码的调试。
调试,是程序员的必备基础日常技能。
参加工作以来,自己学习的第一门语言是PHP,当时调试的主要手段是var_dump/echo和打印log,写的很嗨皮。19年学习go语言后,接触到delve调试工具,遇到一些比较难解的case均通过delve工具来解决,但很惭愧,自己的delve工具均是通过shell在命令行环境下进行调试,如果项目代码比较庞大,shell确实效率低一些。自己不用编辑器的原因是自己的笔记本电脑并不是自己的开发环境,有过工作的童鞋有了解,笔记本电脑一般都是「UI层」,代码需要跑在开发机(Linux)上,开发机与线上的环境基本一致,后续的agile流水自动集成和线上部署均是丝滑的。示意图如下。
问题在哪里呢,问题就是出在本地环境Mac和开发环境Centos环境不一致这个上面。
这里得稍微赘述下,Go语言是编译型语言,Java比较特殊,可以说是编译型的语言,也可以说是解释型的语言,这里为陈述简单,暂且将为归类为编译型语言。
2 学习过程
2.1 「农业时代」 JDB
由于在Go中用shell的dlv习惯了,所以Java应该也有对应的shell命令,查了下是JDB。调试过程如下
0. 安装JAVA基础环境
- 下载JDK https://www.oracle.com/java/technologies/downloads/
- 解压,设置对应的环境变量
# 编辑
# vim /etc/profile
export JAVA_PATH=/home/work/new/jdk1.8.0_351/bin/
export PATH=$JAVA_PATH:$PATH
# 生效
# source /etc/profile
- 安装成功标志
$ java -version
java version "1.8.0_351"
Java(TM) SE Runtime Environment (build 1.8.0_351-b10)
Java HotSpot(TM) Server VM (build 25.351-b10, mixed mode)
$ javac -version
javac 1.8.0_351
A. 准备一个源程序
目录结构如下(bin下的HelloJDB.class是后来生成的)
.
├── bin
│ └── HelloJDB.class
└── src
└── HelloJDB.java
./src/HelloJDB.java 源代码如下
1 public class HelloJDB {
2 public static void main(String[] args) {
3 int i = 5;
4 int j = 6;
5 int sum = add(i, j);
6 System.out.println(sum);
7
8 sum = 0;
9 for(i=0; i< 100; i++)
10 sum += i;
11
12 System.out.println(sum);
13 }
14
15 public static int add(int augend, int addend){
16 int sum = augend + addend;
17 return sum;
18 }
19 }
B. 编译源代码
javac -g -d bin/ src/HelloJDB.java
生成的class文件在 ./bin 目录下
C. 开始调试
$ cd ./bin/
$ jdb -sourcepath ../src/:. HelloJDB
../src 找到java文件,方便调试过程中看源代码
: 分隔符号
. 当前class目录
Initializing jdb ...
在主函数下断点
> stop in HelloJDB.main
Deferring breakpoint HelloJDB.main.
It will be set after the class is loaded.
运行
> run
run HelloJDB
Set uncaught java.lang.Throwable
Set deferred uncaught java.lang.Throwable
>
VM Started: Set deferred breakpoint HelloJDB.main
Breakpoint hit: "thread=main", HelloJDB.main(), line=3 bci=0
3 int i = 5;
运行一步
main[1] step
>
Step completed: "thread=main", HelloJDB.main(), line=4 bci=2
4 int j = 6;
查看当前的运行位置
main[1] list
1 public class HelloJDB {
2 public static void main(String[] args) {
3 int i = 5;
4 => int j = 6;
5 int sum = add(i, j);
6 System.out.println(sum);
7
8 sum = 0;
9 for(i=0; i< 100; i++)
10 sum += i;
打印i
main[1] print i
i = 5
main[1] quit
总结,用jdb体验感觉比较差,感觉没有dlv用的丝滑(dlv debug main.go 开始调试),单步调试和加断点在shell中操作也比较麻烦。痛定思痛,上编辑器调试。
2.2 「工业时代」VS Code
用VS Code面临的第一个问题是我们的项目代码是在本地上还是开发机上。 这样描述还不够精确。
引用大佬的一段话,感觉描述的挺准确的。
如果按照代码位置再区分 local 还是 remote ,那么姿势就可以分为:
- 本地 launch 调试:vscode 在本机,代码在本地,二进制在本地;
- 本地 attach 调试:vscode 在本机,代码在本地,进程在本地;
- 远程 lanuch 调试:vscode 在本机,代码远端,二进制在远端;
- 远程 attach 调试:vscode 在本机,代码在本地,二进制在远端;
这里我们首先考虑情况4,这种最为强大(坑也多)
在进行调试之前,要做的准备工作是,在MAC电脑上安装 Java/Maven,保持与Centos上面的Java/Maven保持一致的版本。maven下载地址,https://maven.apache.org/,maven解压后设置环境变量。另外,准备好一个maven项目(简单的项目不用maven也是ok的,用maven是为了贴近实际的情况)
开发机上运行,确保项目可以正常启动,8000端口已经正常启动
mvnDebug spring-boot:run -Dspring-boot.run.jvmArguments="-agentlib:jdwp=transport=dt_socket,server=y,suspend=y,address=8000"
本机MAC上启动VS Code,先下载插件 Debugger for Java,如下图
将开发机的maven项目代码copy到本地一份。
注意!!!,目录一定是./src目录,不能是上层或者下层,否则vscode调试会报错(这个坑踩了,耽误了不少时间)。
具体的tree目录如图所示才可以,一定注意。
下面开始操作啦,点击创建launch.json
选调试器 Java
生成的文件如下,其实这个文件就会生成在顶级目录下,
修改内容如下,保持,之后重启项目
{
"type": "java",
"name": "Launch BlogserverApplication",
"request": "attach", // 远程attach模式
"hostName": "xxx", // 开发机hostname
"port": "8000", // 开发机开的端口,上面mvnDebug开的是哪个端口,这个就填写哪个端口
"projectName": "blogserver",
"sourcePaths": ["/Users/xxx/Downloads/VBlog-master/blogserver/"] // 重要~~!!!~~本地的代码位置,方便待会加断点
}
开始调试
看到开发机上的服务已经启动了,就说明已经attach上去了
如果展示不出来这个地方,可以点下重启,亲测有效
加断点,开始调试,随便找一个地方加一下
因为我这个项目是http的服务,curl一下,可以看到已经捕捉到
之后就可以开心的调试啦,看着内容很多,其实掌握几个关键点之后,还是比较容易掌握的。
3 提炼出来的经验
1 遇到不懂的问题,需要慢下来,慢下来一点点看,越着急找到答案,可能反而容易乱
2 针对不懂的基础问题,不能绕过,直面问题,而且一定要把这类基本问题通过输出的方式沉淀下来,通过输出才能倒逼自己把这块盲点吃透
3 看别人博客/看书学会->第一级,能够调通/跑通->第二级,写文章输出->第三级,帮别人解决类似问题->第四级,基础问题基本上要达到第四级的标准
4 技术原理
最核心的技术原理是JDB ATTACH。vscode为啥可以通过sourcePaths 参数直接下断点,这是因为,本地代码和开发机的相同,在这里下断点,相当于vscode帮我们加了断点。所以可以做到「看起来在本地调试,其实是调试远端程序的过程」
5 参考文章
[0] vscode 官网文档 https://code.visualstudio.com/docs/java/java-debugging
[1] java调试那点事 https://developer.aliyun.com/article/56
[2] vscode 调试技巧 https://www.modb.pro/db/377704