最近在debug dubbo代码过程中遇到的很有趣的问题

我们都知道dubbo ReferenceBean是消费者的spring
bean包装,为了查一个consumer端的问题,在ReferenceBean的父类ReferenceConfig的 T
get()方法(140行)打上了一个断点。

当我debug
跟进init方法之后发现,ReferenceConfig的成员变量initialized(boolean类型),没有初始化,值变成了true? 纳尼。。。

在学习java的基础知识的时候,我们就知道如果boolean类型如果不初始化变量,运行的时候默认初始为true。为什么变量initialized没有赋值的情况,值是true呢?


更奇怪的是,debug模式下,因为initialized=true
consumer的桩代码(proxy)没有生成,所以在业务层调用的时候跑出了NPE;但是在run模式下是对的。

初步怀疑


初步怀疑是debug模式和run模式下初始化的值是不同的,然后上google去搜索一下是不是存在这个问题,可惜没有任何的收获;同时在初始化的时候,直接把initialized初始化为false,防止缺省值初始成true。
但是问题依旧,放弃了这条思路!!!

然后开始怀疑是IDEA编辑器是不是在断点处有setvalue的情况,就把IDEA全部缓存清空并重启了(File->Invalidate....),debug后问题依然!!!

修改dubbo的源代码加日志输出

实在没什么思路了,想着先去增加一些日志输出,办法虽然很土,但是可能会有线索。在initialized=true 这行代码之后加一行输出
System.out.println("init initialized="+initialized);

同时断点还在ReferenceConfig.get()方法里面


当运行到断点出,观察console的输出,果然有输出!!!!



这说明当我断点在ReferenceConfig.get()方法里时候,有线程执行了init()方法导致initialized的值被修改成了true(dubbo代码只有一处修改ReferenceConfig.initialized值的地方,就在init里面)
所以只要找出哪个线程在我断点的时候,执行了init方法就行了

日志输出又立大功

继续在init方法里面加日志输出,以下日志能显示出哪个堆栈调用了init方法


继续debug运行,得到结果出乎意外



从日志输出可以看出来,在ReferenceConfig构造函数的地方,调用了父类AbstractConfig.toString方法,而在AbstractConfig的toString方法里面反射间接调用了ReferenceConfig.init()方法
这下算是找到谁在我断点的时候调用了ReferenceConfig.init()方法,就是toString()方法。
但是谁调用了toString()方法呢?

真想大白

首先可以排除程序在构造函数里面调用AbstractConfig.toString方法,还有一种可能就是IDEA
为了显示触发了这个类实例的toString方法。有了这个假设思路,写了一个demo验证一下



果不其然console里面输出了invoke toString()

总结

IDEA 这类编辑器带debug功能为了断点处能显示一个类的实例,就会反射调用实例的toString!!!!
真是一个有趣的发现!!!!

附送dubbo ReferenceConfig源码链接
<https://github.com/apache/incubator-dubbo/blob/d129f10229869bb8be3aff0787cd6303eb0e5ad0/dubbo-config/dubbo-config-api/src/main/java/com/alibaba/dubbo/config/ReferenceConfig.java>

友情链接
KaDraw流程图
API参考文档
OK工具箱
云服务器优惠
阿里云优惠券
腾讯云优惠券
华为云优惠券
站点信息
问题反馈
邮箱:ixiaoyang8@qq.com
QQ群:637538335
关注微信