远程Debug的错误坑从何来来自于我的开源小工具

前言

昨天看到一个问题,“疫情结束后你最想吃什么?”

仔细想想,火锅?烧烤?

看了看体重秤,怕是只能报名健身房了。

你以为你胖 N 磅的时间复杂度是 O(2^N),实际上它是 O(1),嗖。

文本

回到主题

说到远程调试的功能,基本上大部分IDE都会自带,但一般很少用!

切换到IDEA之后,我真的没用过远程调试b本地调试工具,直到昨天发现一个非常基本的错误。

坑是从哪里来的

从我的开源小工具:

作者的初衷是打造一个简单、轻量、一键式界面模拟系统,方便前后端同学等待别人的界面。

基于以上目的,我使用嵌入式数据库sqlite配合Springboot,构建了一个无需配置,一行启动的小jar包。目录结构如下,直接把数据库扔到Resource中:

开源后,有使用的同学提出了一个bug,作者也正常操作。修正错误后,版本重新发布。

升级版本的同学发现数据没了。笔者暂时给出了一个方案。它是一个嵌入式数据库。只需将旧jar中的数据库文件覆盖到新jar中即可。

(其中DB文件位于jar包中)

当我这么说的时候,我不能完全依赖瓦特。毕竟Springboot+Sqlite的奇妙组合,也是为了工具的紧凑性偶尔尝试的产物。

其实稍微想一想b本地调试工具,db文件和其他资源不同,需要经常重写。当然,改变的并不是jar包中的原文件。

直到收到一个Issue,告诉作者将DB文件复制到新jar没有生效。

笔者也很快反应过来,jar里的db文件怎么能用呢,真实的文件居然没有放在java.io.tmpdir下面。

java.io.tmpdir的路径,一般情况下macos在$TMPDIR,win在%temp%。

笔者也切换到对应目录,终于看到了jar运行时实际使用的DB文件:

但是这种命名方式很奇怪,和原来的v-mock.sqlite没有任何关系。

一路跟着sqlite的jdbc驱动源码,找到了org.sqlite.SQLiteConnection的extractResource方法,看到了命名代码:

其实很明显,源码使用sqlite-jdbc-tmp拼接原始jar中DB文件的URL类的hashcode作为文件名。

之所以我开发的时候没有注意到,就看一下这个方法的第一个if判断。

笔者习惯在IDE中使用Springboot或者Application方式直接启动项目,而不是打包的启动方式

所以当Protocol是文件而不是jar时,直接使用target/classes/db/v-mock.sqlite文件,不生成临时文件。

在开发的时候,DB可视化工具也连接到target/classes/db/v-mock.sqlite,所以当时没有发现任何疑问。

其实这是很正常的操作。很多地方的源码已经判断是正常的web环境还是jar运行。如果有这方面的调试,需要考虑一下自己的启动方式。

然后如果你想在第一个 if 之后下断点并查看效果,其中一个选项是使用远程 Debug 方法。

IDEA 的远程调试

IDEA 的远程 Debug 模块在设计上真的很用心。傻瓜都可以操作,命令全部生成。不知道现在的eclipse版本有没有这么贴心。

从配置中搜索远程模板,点击右上角的创建配置,远程调试启动方法就创建好了。

在调试器模式下,您可以选择附加到远程 JVM。它还有一个Listen to remote JVM的选项,顾名思义,一个是主动附加到启动的程序,另一个是被动监听。

ip和port不用说,作者直接使用本地jar包,所以填写localhost,如果右边jdk版本使用其他版本,需要调整。

中间的文本框是生成的jvm参数,非常人性化,直接添加启动命令即可

java -jar -agentlib:jdwp=transport=dt_socket,server=y,suspend=n,address=5005 v-mock.jar

您可以完全忽略命令的含义。想知道的话,作者大致解释一下:

启动jar包,然后按照刚才创建的方式调试,已经成功到达预期的断点位置。

结尾

找到原因后,作者还按照 sqliteJDBC 源码中的命名方式开发了一种数据迁移方法。

即:自动或手动查找上一版本的数据库文件,制作一份,并以新版本的hashcode命名。

Springboot + 嵌入式数据库是一个很“不雅”的组合,但是小工具的开发还是相当不错的。如果遇到同样的数据迁移问题,可以参考作者的解决方案。

© 版权声明
THE END
喜欢就支持一下吧
点赞0
分享
评论 抢沙发

请登录后发表评论