自底向上代码调试技巧
原创:打码日记(微信公众号ID:codelogs),欢迎分享,转载请保留出处。
简介#
我们常使用IDE的调试功能解决程序问题,但很多同学用的是自上而下调试法,即找到一个代码入口,打上断点然后单步调试。
但一些特殊的调试场景,比如调试框架代码,在不太熟悉框架代码的情况,会因为不知道从哪个入口开始调试而感到迷茫,这时可以试试本文介绍的方法。
例子#
比如,我们写了一个接口,在获取参数的时候乱码了如下:
如何快速定位这个问题呢?
众所周知,乱码基本都是因为请求方与服务方字符集配置不一致产生的,比如请求方使用UTF-8,服务方使用GBK。
另外,既然上述接口中参数定义的是String类型,那么spring或tomcat框架中一定有个地方将网络请求中的字节流数据转换成这个String对象。
那么就可以这样,我们在String类的所有构造方法中加入条件断点,加断点后在断点处点鼠标右键即可添加条件,比如new String().contains("abcdefg")
,然后请求这个接口时使用一个特殊的参数值abcdefg
,这样当框架中new出包含abcdefg
的String对象时,我们的条件断点就会命中,如下:
在String中添加条件断点后,我们重启应用,发如下请求来触发断点:
curl http://192.168.0.103:8080/test?data=abcdefg
我们往调用栈上面看,发现是handleQueryParameters
中创建字符串时使用的GBK来new出String,而GBK来自queryStringCharset
属性,如下:
那是哪里配置成了GBK
呢?我们再在设置queryStringCharset
属性的地方,即setQueryStringCharset
方法加入断点,重启应用并重新发送请求(重启是为避免缓存导致断点触发不了),如下:
我们再往调用栈上面看,发现setQueryStringCharset
的参数来自connector.getURICharset()
,如下:
同理,我们在赋值connector.setURICharset
的地方打上断点,重启应用,发现在重启的过程中就命中了断点,如下:
我们再往调用栈上面看,发现connector.setURICharset
的参数来自this.getUriEncoding()
方法,而this是TomcatServletWebServerFactory
类型
同理,我们在TomcatServletWebServerFactory.setUriEncoding
方法加上断点,重启应用,如下:
我们再往调用栈上面看,在to(Consumer<T> consumer)
方法中发现uriEncoding来自this.supplier.get()
,而this.supplier.get()
取的应该就是ServerProperties$Tomcat
对象中的urlEncoding属性
同理,我们在它的setter方法ServerProperties$Tomcat.setUriEncoding
里面加上断点,重启应用,如下:
我们再往调用栈上面看,发现uriEncoding是从JavaBeanBinder.bind
方法设置进来,从调用方法命名上不难看出,这个方法应该就是将配置文件中的值set到配置类属性中去的,当前被配置的类是ServerProperties$Tomcat
,而正在配置的属性是uri-encoding
,如下:
我们在此处瞄下各变量与参数的组成,很快就在BeanPropertyBinder
参数中找到,uriEncoding来自application-web.yml
文件的第4行第19列,如下:
果真,在application-web.yml
中第4行,配置了uri-encoding: GBK
,如下:
ok,通过这个例子,相信你已经体会到自底向上调试方法的诀窍了。
总结#
上面这个例子其实可以有更快处理方法,比如在当前工程全文搜索GBK
,又或者google一下springboot
,乱码
之类的关键词,也能很快解决问题,但思路是很重要的,比如类似下面的场景,也能运用这里的方法:
- 系统运行时,不知道什么地方的代码老是执行了一条删除的sql,我们可以和上面一样,在String里面打上条件断点,条件是包含删除sql的部分片段。
- 系统启动时,不知道什么地方的代码监听了12345端口,我们可以在
ServerSocket
里面加上条件断点,条件是port==12345
。 - 系统运行时,不知道什么地方的代码老是写
/tmp/app.log
文件,我们可以在FileOutputStream.write
方法加上条件断点,条件是File=="/tmp/app.log"
。
往期内容#
真正理解可重复读事务隔离级别
Linux文本命令技巧(下)
Linux文本命令技巧(上)
原来awk真是神器啊
常用网络命令总结
作者:打码日记
出处:https://www.cnblogs.com/codelogs/p/16060221.html
版权:本作品采用「署名-非商业性使用-相同方式共享 4.0 国际」许可协议进行许可。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· Manus重磅发布:全球首款通用AI代理技术深度解析与实战指南
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
· 没有Manus邀请码?试试免邀请码的MGX或者开源的OpenManus吧
· 园子的第一款AI主题卫衣上架——"HELLO! HOW CAN I ASSIST YOU TODAY
· 【自荐】一款简洁、开源的在线白板工具 Drawnix